@cofhe/sdk 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/acps/acp.ts +411 -0
  3. package/acps/index.ts +70 -0
  4. package/{permits → acps}/onchain-utils.ts +49 -24
  5. package/acps/sealing.ts +90 -0
  6. package/acps/signature.ts +89 -0
  7. package/acps/store.ts +172 -0
  8. package/acps/test/acp.test.ts +615 -0
  9. package/acps/test/localstorage.test.ts +105 -0
  10. package/acps/test/sealing.test.ts +77 -0
  11. package/acps/test/store.test.ts +88 -0
  12. package/acps/test/validation.test.ts +361 -0
  13. package/acps/test-utils.ts +32 -0
  14. package/acps/types.ts +252 -0
  15. package/acps/validation.ts +392 -0
  16. package/adapters/test/ethers5.test.ts +4 -1
  17. package/adapters/test/ethers6.test.ts +4 -1
  18. package/adapters/test/wagmi.test.ts +5 -2
  19. package/chains/chains/stagingCofhe.ts +21 -0
  20. package/chains/index.ts +3 -1
  21. package/chains/test/chains.test.ts +2 -1
  22. package/core/acps.ts +625 -0
  23. package/core/client.ts +136 -39
  24. package/core/clientTypes.ts +52 -41
  25. package/core/config.ts +66 -5
  26. package/core/debug.ts +72 -0
  27. package/core/decrypt/MockThresholdNetworkAbi.ts +20 -11
  28. package/core/decrypt/apiError.ts +104 -0
  29. package/core/decrypt/cofheMocksDecryptForTx.ts +11 -11
  30. package/core/decrypt/cofheMocksDecryptForView.ts +7 -7
  31. package/core/decrypt/decryptForTxBuilder.ts +102 -102
  32. package/core/decrypt/decryptForViewBuilder.ts +90 -90
  33. package/core/decrypt/submitRetry.ts +38 -30
  34. package/core/decrypt/tnDecryptV1.ts +5 -5
  35. package/core/decrypt/tnDecryptV2.ts +45 -34
  36. package/core/decrypt/tnSealOutputV1.ts +4 -3
  37. package/core/decrypt/tnSealOutputV2.ts +44 -31
  38. package/core/encrypt/cofheMocksZkVerifySign.ts +59 -74
  39. package/core/encrypt/encryptInputsBuilder.ts +86 -52
  40. package/core/encrypt/zkPackProveVerify.ts +25 -18
  41. package/core/error.ts +34 -6
  42. package/core/index.ts +14 -14
  43. package/core/test/acpDefaults.test.ts +52 -0
  44. package/core/test/acps.test.ts +596 -0
  45. package/core/test/apiError.test.ts +130 -0
  46. package/core/test/client.test.ts +22 -19
  47. package/core/test/config.test.ts +25 -5
  48. package/core/test/decrypt.test.ts +40 -35
  49. package/core/test/decryptBuilders.test.ts +68 -68
  50. package/core/test/decryptErrorCodes.test.ts +217 -0
  51. package/core/test/encryptInputsBuilder.test.ts +72 -41
  52. package/core/test/pollCallbacks.test.ts +89 -18
  53. package/core/test/stagingRedirect.ts +18 -0
  54. package/core/test/submitRetry.test.ts +182 -0
  55. package/core/types.ts +9 -69
  56. package/dist/acp-Wi6isVQI.d.cts +407 -0
  57. package/dist/acp-Wi6isVQI.d.ts +407 -0
  58. package/dist/acps.cjs +1081 -0
  59. package/dist/acps.d.cts +480 -0
  60. package/dist/acps.d.ts +480 -0
  61. package/dist/acps.js +2 -0
  62. package/dist/chains.cjs +14 -1
  63. package/dist/chains.d.cts +30 -1
  64. package/dist/chains.d.ts +30 -1
  65. package/dist/chains.js +1 -1
  66. package/dist/{chunk-PE5V5CCV.js → chunk-43USWPEH.js} +1000 -604
  67. package/dist/{chunk-MTRAXQXC.js → chunk-N6IDQRRU.js} +14 -2
  68. package/dist/chunk-Q7CBWGQX.js +1029 -0
  69. package/dist/{clientTypes-CyUvRRzA.d.ts → clientTypes-BN3nbzYM.d.ts} +342 -165
  70. package/dist/{clientTypes-BDy1qIBu.d.cts → clientTypes-CYZjFznO.d.cts} +342 -165
  71. package/dist/core.cjs +1431 -1026
  72. package/dist/core.d.cts +55 -10
  73. package/dist/core.d.ts +55 -10
  74. package/dist/core.js +3 -3
  75. package/dist/node.cjs +1356 -976
  76. package/dist/node.d.cts +2 -2
  77. package/dist/node.d.ts +2 -2
  78. package/dist/node.js +3 -3
  79. package/dist/web.cjs +1356 -976
  80. package/dist/web.d.cts +2 -2
  81. package/dist/web.d.ts +2 -2
  82. package/dist/web.js +3 -3
  83. package/node/test/inherited.test.ts +75 -65
  84. package/node/test/tfheinit.test.ts +23 -8
  85. package/package.json +6 -6
  86. package/web/test/client.web.test.ts +5 -1
  87. package/web/test/inherited.web.test.ts +75 -65
  88. package/web/test/tfheinit.web.test.ts +14 -5
  89. package/web/test/worker.config.web.test.ts +38 -23
  90. package/web/test/worker.output.web.test.ts +25 -24
  91. package/core/encrypt/encryptUtils.ts +0 -67
  92. package/core/permits.ts +0 -206
  93. package/core/test/permits.test.ts +0 -534
  94. package/dist/chunk-VB62WYPL.js +0 -978
  95. package/dist/permit-DnVMDT5h.d.cts +0 -376
  96. package/dist/permit-DnVMDT5h.d.ts +0 -376
  97. package/dist/permits.cjs +0 -1026
  98. package/dist/permits.d.cts +0 -353
  99. package/dist/permits.d.ts +0 -353
  100. package/dist/permits.js +0 -2
  101. package/permits/index.ts +0 -68
  102. package/permits/permit.ts +0 -385
  103. package/permits/sealing.ts +0 -131
  104. package/permits/signature.ts +0 -79
  105. package/permits/store.ts +0 -157
  106. package/permits/test/localstorage.test.ts +0 -113
  107. package/permits/test/permit.test.ts +0 -557
  108. package/permits/test/sealing.test.ts +0 -84
  109. package/permits/test/store.test.ts +0 -88
  110. package/permits/test/validation.test.ts +0 -361
  111. package/permits/test-utils.ts +0 -28
  112. package/permits/types.ts +0 -204
  113. package/permits/validation.ts +0 -327
  114. /package/{permits → acps}/utils.ts +0 -0
@@ -0,0 +1,182 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { classifySubmitResponse, throwIfSubmitRetryTimedOut } from '../decrypt/submitRetry.js';
3
+ import { CofheError, CofheErrorCode } from '../error.js';
4
+
5
+ const makeResponse = (opts: {
6
+ ok: boolean;
7
+ status: number;
8
+ statusText?: string;
9
+ json: () => Promise<unknown>;
10
+ }): Response => {
11
+ return {
12
+ ok: opts.ok,
13
+ status: opts.status,
14
+ statusText: opts.statusText ?? '',
15
+ json: opts.json,
16
+ } as unknown as Response;
17
+ };
18
+
19
+ describe('classifySubmitResponse', () => {
20
+ it('classifies 204 as retryable without reading the body', async () => {
21
+ const json = vi.fn(async () => {
22
+ throw new Error('json() should not be called for 204');
23
+ });
24
+ const response = makeResponse({ ok: true, status: 204, json });
25
+
26
+ const result = await classifySubmitResponse({ response, fallbackErrorCode: CofheErrorCode.DecryptFailed });
27
+
28
+ expect(result).toEqual({ kind: 'retryable', status: 204 });
29
+ expect(json).not.toHaveBeenCalled();
30
+ });
31
+
32
+ it('classifies 200 as parse-json', async () => {
33
+ const response = makeResponse({ ok: true, status: 200, json: async () => ({}) });
34
+
35
+ const result = await classifySubmitResponse({ response, fallbackErrorCode: CofheErrorCode.DecryptFailed });
36
+
37
+ expect(result).toEqual({ kind: 'parse-json' });
38
+ });
39
+
40
+ it('classifies 404 with error=ct_not_found as retryable', async () => {
41
+ const response = makeResponse({
42
+ ok: false,
43
+ status: 404,
44
+ json: async () => ({ error: 'ct_not_found', error_message: 'ciphertext not indexed yet' }),
45
+ });
46
+
47
+ const result = await classifySubmitResponse({ response, fallbackErrorCode: CofheErrorCode.DecryptFailed });
48
+
49
+ expect(result).toEqual({ kind: 'retryable', status: 404, apiErrorMessage: 'ciphertext not indexed yet' });
50
+ });
51
+
52
+ it('classifies 404 with a different error code as retryable', async () => {
53
+ const response = makeResponse({
54
+ ok: false,
55
+ status: 404,
56
+ json: async () => ({ error: 'acp_denied', error_message: 'acp was rejected' }),
57
+ });
58
+
59
+ const result = await classifySubmitResponse({ response, fallbackErrorCode: CofheErrorCode.DecryptFailed });
60
+
61
+ expect(result).toEqual({
62
+ kind: 'retryable',
63
+ status: 404,
64
+ apiErrorMessage: 'acp was rejected',
65
+ });
66
+ });
67
+
68
+ it('classifies 404 with an unparsable body as retryable', async () => {
69
+ const response = makeResponse({
70
+ ok: false,
71
+ status: 404,
72
+ statusText: 'Not Found',
73
+ json: async () => {
74
+ throw new Error('not json');
75
+ },
76
+ });
77
+
78
+ const result = await classifySubmitResponse({ response, fallbackErrorCode: CofheErrorCode.DecryptFailed });
79
+
80
+ expect(result).toEqual({
81
+ kind: 'retryable',
82
+ status: 404,
83
+ apiErrorMessage: 'Not Found',
84
+ });
85
+ });
86
+
87
+ it('classifies other non-ok statuses as fatal with the mapped error code', async () => {
88
+ const response = makeResponse({
89
+ ok: false,
90
+ status: 500,
91
+ json: async () => ({ error: 'internal_error', error_message: 'decrypt task panicked' }),
92
+ });
93
+
94
+ const result = await classifySubmitResponse({ response, fallbackErrorCode: CofheErrorCode.SealOutputFailed });
95
+
96
+ expect(result).toEqual({
97
+ kind: 'fatal-http',
98
+ status: 500,
99
+ cofheErrorCode: CofheErrorCode.InternalError,
100
+ apiErrorCode: 'internal_error',
101
+ errorMessage: 'decrypt task panicked',
102
+ });
103
+ });
104
+ });
105
+
106
+ describe('throwIfSubmitRetryTimedOut', () => {
107
+ const baseParams = {
108
+ operationLabel: 'decrypt',
109
+ errorCode: CofheErrorCode.DecryptFailed,
110
+ thresholdNetworkUrl: 'http://threshold.local',
111
+ body: { some: 'body' },
112
+ attemptIndex: 3,
113
+ };
114
+
115
+ it('does not throw when under both budgets', () => {
116
+ expect(() =>
117
+ throwIfSubmitRetryTimedOut({
118
+ ...baseParams,
119
+ status: 204,
120
+ elapsedMs: 1000,
121
+ retry404TimeoutMs: 10_000,
122
+ overallTimeoutMs: 300_000,
123
+ })
124
+ ).not.toThrow();
125
+ });
126
+
127
+ it('throws CtNotFound with the last-known message once the 404 retry budget elapses', () => {
128
+ try {
129
+ throwIfSubmitRetryTimedOut({
130
+ ...baseParams,
131
+ status: 404,
132
+ elapsedMs: 10_001,
133
+ retry404TimeoutMs: 10_000,
134
+ overallTimeoutMs: 300_000,
135
+ lastKnownErrorMessage: 'ciphertext not indexed yet',
136
+ });
137
+ expect.fail('expected throwIfSubmitRetryTimedOut to throw');
138
+ } catch (error) {
139
+ expect(error).toBeInstanceOf(CofheError);
140
+ const cofheError = error as CofheError;
141
+ expect(cofheError.code).toBe(CofheErrorCode.CtNotFound);
142
+ expect(cofheError.apiErrorCode).toBe('ct_not_found');
143
+ expect(cofheError.message).toBe(
144
+ 'decrypt ciphertext not found after retrying for 10000ms: ciphertext not indexed yet'
145
+ );
146
+ }
147
+ });
148
+
149
+ it('omits the trailing message when no lastKnownErrorMessage is available', () => {
150
+ try {
151
+ throwIfSubmitRetryTimedOut({
152
+ ...baseParams,
153
+ status: 404,
154
+ elapsedMs: 10_001,
155
+ retry404TimeoutMs: 10_000,
156
+ overallTimeoutMs: 300_000,
157
+ });
158
+ expect.fail('expected throwIfSubmitRetryTimedOut to throw');
159
+ } catch (error) {
160
+ const cofheError = error as CofheError;
161
+ expect(cofheError.message).toBe('decrypt ciphertext not found after retrying for 10000ms');
162
+ }
163
+ });
164
+
165
+ it('throws the generic operation error once the overall timeout elapses (204)', () => {
166
+ try {
167
+ throwIfSubmitRetryTimedOut({
168
+ ...baseParams,
169
+ status: 204,
170
+ elapsedMs: 300_001,
171
+ retry404TimeoutMs: 10_000,
172
+ overallTimeoutMs: 300_000,
173
+ });
174
+ expect.fail('expected throwIfSubmitRetryTimedOut to throw');
175
+ } catch (error) {
176
+ const cofheError = error as CofheError;
177
+ expect(cofheError.code).toBe(CofheErrorCode.DecryptFailed);
178
+ expect(cofheError.apiErrorCode).toBeUndefined();
179
+ expect(cofheError.message).toBe('decrypt submit retried without receiving request_id for 300000ms');
180
+ }
181
+ });
182
+ });
package/core/types.ts CHANGED
@@ -111,43 +111,6 @@ export type EncryptedNumber = {
111
111
  securityZone: number;
112
112
  };
113
113
 
114
- export type EncryptedItemInput = {
115
- ctHash: bigint;
116
- securityZone: number;
117
- utype: FheTypes;
118
- signature: `0x${string}`;
119
- };
120
-
121
- export function assertCorrectEncryptedItemInput(input: EncryptedItemInput): asserts input is EncryptedItemInput {
122
- if (!input.signature.startsWith('0x')) throw new Error('Signature must be a hex string starting with 0x');
123
- }
124
-
125
- export type EncryptedBoolInput = EncryptedItemInput & {
126
- utype: FheTypes.Bool;
127
- };
128
- export type EncryptedUint8Input = EncryptedItemInput & {
129
- utype: FheTypes.Uint8;
130
- };
131
- export type EncryptedUint16Input = EncryptedItemInput & {
132
- utype: FheTypes.Uint16;
133
- };
134
- export type EncryptedUint32Input = EncryptedItemInput & {
135
- utype: FheTypes.Uint32;
136
- };
137
- export type EncryptedUint64Input = EncryptedItemInput & {
138
- utype: FheTypes.Uint64;
139
- };
140
- export type EncryptedUint128Input = EncryptedItemInput & {
141
- utype: FheTypes.Uint128;
142
- };
143
- // [U256-DISABLED]
144
- // export type EncryptedUint256Input = EncryptedItemInput & {
145
- // utype: FheTypes.Uint256;
146
- // };
147
- export type EncryptedAddressInput = EncryptedItemInput & {
148
- utype: FheTypes.Uint160;
149
- };
150
-
151
114
  export type EncryptableBase<U extends FheTypes, D> = {
152
115
  data: D;
153
116
  securityZone: number;
@@ -321,34 +284,6 @@ export type EncryptableItemByFheType<T extends FheTypes> = T extends FheTypes.Bo
321
284
  ? EncryptableAddress
322
285
  : never;
323
286
 
324
- // COFHE Encrypt
325
- export type EncryptableToEncryptedItemInputMap<E extends EncryptableItem> = E extends EncryptableBool
326
- ? EncryptedBoolInput
327
- : E extends EncryptableUint8
328
- ? EncryptedUint8Input
329
- : E extends EncryptableUint16
330
- ? EncryptedUint16Input
331
- : E extends EncryptableUint32
332
- ? EncryptedUint32Input
333
- : E extends EncryptableUint64
334
- ? EncryptedUint64Input
335
- : E extends EncryptableUint128
336
- ? EncryptedUint128Input
337
- : // [U256-DISABLED]
338
- // : E extends EncryptableUint256
339
- // ? EncryptedUint256Input
340
- E extends EncryptableAddress
341
- ? EncryptedAddressInput
342
- : never;
343
-
344
- export type EncryptedItemInputs<T> = T extends Primitive
345
- ? LiteralToPrimitive<T>
346
- : T extends EncryptableItem
347
- ? EncryptableToEncryptedItemInputMap<T>
348
- : {
349
- [K in keyof T]: EncryptedItemInputs<T[K]>;
350
- };
351
-
352
287
  export function isEncryptableItem(value: unknown): value is EncryptableItem {
353
288
  return (
354
289
  // Is object and exists
@@ -399,7 +334,12 @@ export type ExternalUint64Hash = `0x${string}` & { readonly utype: FheTypes.Uint
399
334
  export type ExternalUint128Hash = `0x${string}` & { readonly utype: FheTypes.Uint128 };
400
335
  export type ExternalAddressHash = `0x${string}` & { readonly utype: FheTypes.Uint160 };
401
336
 
402
- /** Branded bytes proof blob (Solidity: bytes memory proof). */
337
+ /**
338
+ * Branded batch signature (Solidity: bytes memory signature).
339
+ * A single ECDSA signature (65-byte r||s||v, hex-encoded) authenticating an entire batch of
340
+ * ciphertexts at once — it covers keccak256(h_0 || h_1 || ... || h_n), where each h_i is the
341
+ * per-ciphertext message hash for the corresponding ExternalItemHashes entry, in order.
342
+ */
403
343
  export type ExternalHashProof = `0x${string}` & { readonly _kind: 'ExternalHashProof' };
404
344
 
405
345
  /** Union of all External*Hash types — useful for utilities that operate on any hash without caring about the specific FHE type. */
@@ -414,7 +354,6 @@ export type AnyExternalHash =
414
354
 
415
355
  /**
416
356
  * Maps a single EncryptableItem to its corresponding External*Hash type.
417
- * Mirrors EncryptableToEncryptedItemInputMap.
418
357
  */
419
358
  export type EncryptableToExternalHashMap<E extends EncryptableItem> = E extends EncryptableBool
420
359
  ? ExternalBoolHash
@@ -441,8 +380,9 @@ export type ExternalItemHashes<T extends EncryptableItem[]> = {
441
380
  };
442
381
 
443
382
  /**
444
- * Return type of EncryptInputsBuilder.execute() when asHashPlusProof() is set.
445
- * Tuple of per-input hashes in input order, followed by a single proof blob.
383
+ * Return type of EncryptInputsBuilder.execute().
384
+ * Tuple of per-input hashes in input order, followed by the single batch signature that
385
+ * authenticates all of them together.
446
386
  * e.g. [Encryptable.bool(true), Encryptable.uint32(5)] → [ExternalBoolHash, ExternalUint32Hash, ExternalHashProof]
447
387
  */
448
388
  export type HashPlusProofResult<T extends EncryptableItem[]> = [...ExternalItemHashes<T>, ExternalHashProof];
@@ -0,0 +1,407 @@
1
+ import { Hex, PublicClient, WalletClient } from 'viem';
2
+
3
+ type EthEncryptedData = {
4
+ data: Uint8Array;
5
+ public_key: Uint8Array;
6
+ nonce: Uint8Array;
7
+ };
8
+ /**
9
+ * An X25519 sealing keypair, both halves 0x-prefixed 32-byte hex.
10
+ * The public key travels in the ACP (`sealingKey`); the private key never
11
+ * leaves the client (`sealingPrivateKey`).
12
+ */
13
+ type SealingKeyPair = {
14
+ privateKey: Hex;
15
+ publicKey: Hex;
16
+ };
17
+ /**
18
+ * Generates a new sealing keypair. A sealing key is used to encrypt data such
19
+ * that it can only be unsealed (decrypted) by the owner of the corresponding
20
+ * private key.
21
+ */
22
+ declare const GenerateSealingKey: () => SealingKeyPair;
23
+ /**
24
+ * Seals (encrypts) the provided message for a receiver with the specified public key.
25
+ *
26
+ * @param {bigint | number} value - The message to be encrypted.
27
+ * @param {string} publicKey - The public key of the intended recipient (with or without 0x prefix).
28
+ * @returns {EthEncryptedData} - The encrypted message.
29
+ * @throws Will throw if the provided publicKey or value do not meet defined preconditions.
30
+ */
31
+ declare const seal: (value: bigint | number, publicKey: string) => EthEncryptedData;
32
+ /**
33
+ * Unseal (decrypt) data with a sealing private key (with or without 0x prefix).
34
+ * The ephemeral public key travels inside the payload, so the private key alone suffices.
35
+ */
36
+ declare const unsealWithPrivateKey: (privateKey: string, parsedData: EthEncryptedData) => bigint;
37
+
38
+ /**
39
+ * EIP712 related types
40
+ */
41
+ type EIP712Type = {
42
+ name: string;
43
+ type: string;
44
+ };
45
+ type EIP712Types = Record<string, EIP712Type[]>;
46
+ type EIP712Message = Record<string, string>;
47
+ type EIP712Domain = {
48
+ chainId: number;
49
+ name: string;
50
+ verifyingContract: Hex;
51
+ version: string;
52
+ };
53
+
54
+ /**
55
+ * The client-side-only component of an ACP — never leaves the client.
56
+ */
57
+ interface ACPPrivate {
58
+ /**
59
+ * Stable hash of relevant acp data, used as key in storage
60
+ */
61
+ hash: string;
62
+ /**
63
+ * Name for this acp, for organization and UI usage, not included in signature.
64
+ */
65
+ name: string;
66
+ /**
67
+ * The type of the ACP (self / sharing / recipient)
68
+ * (self) ACP that will be signed and used by the issuer
69
+ * (sharing) ACP that is signed by the issuer, but intended to be shared with recipient
70
+ * (recipient) ACP that has been received, and signed by the recipient
71
+ */
72
+ type: 'self' | 'sharing' | 'recipient';
73
+ /**
74
+ * The private half of the sealing keypair — used to unseal returned data.
75
+ * `sealingKey` (in the public component) is the corresponding public key.
76
+ * Never leaves the client.
77
+ */
78
+ sealingPrivateKey: Hex;
79
+ /**
80
+ * EIP712 domain used to sign this acp.
81
+ * Should not be set manually, included in metadata as part of serialization flows.
82
+ */
83
+ _signedDomain?: EIP712Domain;
84
+ }
85
+ /**
86
+ * The public component of an ACP — the signed struct passed on-chain / to the
87
+ * decryption backend to grant encrypted data access. Produced by `getPublic()`.
88
+ */
89
+ interface ACPPublic {
90
+ /**
91
+ * (base) User that initially created the permission, target of data fetching
92
+ */
93
+ issuer: Hex;
94
+ /**
95
+ * (base) Expiration timestamp
96
+ */
97
+ expiration: number;
98
+ /**
99
+ * (sharing) The user that this permission will be shared with
100
+ * ** optional, use `address(0)` to disable **
101
+ */
102
+ recipient: Hex;
103
+ /**
104
+ * (revocation) Opaque data interpreted by `revokerContract` — the default
105
+ * revoker interprets it as the acp's creation timestamp.
106
+ * ** optional, use `0` to disable **
107
+ */
108
+ revokerData: number;
109
+ /**
110
+ * (revocation) The contract to query to determine permission validity
111
+ * ** optional, use `address(0)` to disable **
112
+ */
113
+ revokerContract: Hex;
114
+ /**
115
+ * (scope) Scope discriminator — exactly one scope mode per ACP (see ACPScope).
116
+ * Global: all of `issuer`s values (arrays empty). Contract: values readable by
117
+ * `contracts`. Handles: the listed `handles` only.
118
+ */
119
+ scope: number;
120
+ /**
121
+ * (scope) Grants access to `issuer`s values readable by any of these contracts.
122
+ * Checked on-chain as an intersection with the ACL's persisted allowances.
123
+ */
124
+ contracts: Hex[];
125
+ /**
126
+ * (scope) Grants access to these specific ciphertext handles (bytes32 hex)
127
+ */
128
+ handles: Hex[];
129
+ /**
130
+ * (base) The public half of the sealing keypair — used to re-encrypt `issuer`s confidential data
131
+ * (non-sharing) Populated by `issuer`
132
+ * (sharing) Populated by `recipient`
133
+ */
134
+ sealingKey: Hex;
135
+ /**
136
+ * (base) `signTypedData` signature created by `issuer`.
137
+ * (base) Shared- and Self- permissions differ in signature format: (`sealingKey` absent in shared signature)
138
+ */
139
+ issuerSignature: Hex;
140
+ /**
141
+ * (sharing) `signTypedData` signature created by `recipient`
142
+ * ** required for shared acps **
143
+ */
144
+ recipientSignature: Hex;
145
+ }
146
+ /**
147
+ * Core ACP (Access Control Permission) type — immutable design for React compatibility.
148
+ * The union of the private (client-only) and public (signed) components.
149
+ */
150
+ type ACP = Expand<ACPPrivate & ACPPublic>;
151
+ /**
152
+ * ACP discriminant helpers
153
+ */
154
+ type ACPType = ACP['type'];
155
+ /**
156
+ * Utility type to narrow an ACP to a specific discriminant.
157
+ *
158
+ * Note: this only narrows the `type` field. Runtime/validation constraints
159
+ * (e.g. recipient == zeroAddress for self acps) are enforced elsewhere.
160
+ */
161
+ type ACPOf<T extends ACPType> = Expand<Omit<ACP, 'type'> & {
162
+ type: T;
163
+ }>;
164
+ type SelfACP = ACPOf<'self'>;
165
+ type SharingACP = ACPOf<'sharing'>;
166
+ type RecipientACP = ACPOf<'recipient'>;
167
+ /**
168
+ * Optional additional metadata of an ACP
169
+ * Can be passed into the constructor, but not necessary
170
+ * Useful for deserialization
171
+ */
172
+ interface ACPMetadata {
173
+ /**
174
+ * EIP712 domain used to sign this acp.
175
+ * Should not be set manually, included in metadata as part of serialization flows.
176
+ */
177
+ _signedDomain?: EIP712Domain;
178
+ }
179
+ /**
180
+ * Utility types for acp creation
181
+ */
182
+ /**
183
+ * Scope fields shared by all acp creation options.
184
+ * When any scope array is populated and `global` is not explicitly set,
185
+ * `global` defaults to false (narrowest matching scope); with no scope
186
+ * arrays it defaults to true (V2 behavior).
187
+ */
188
+ declare const ACPScope: {
189
+ readonly Global: 0;
190
+ readonly Contract: 1;
191
+ readonly Handles: 2;
192
+ };
193
+ type ACPScopeOptions = {
194
+ scope?: number;
195
+ contracts?: Hex[];
196
+ handles?: Hex[];
197
+ };
198
+ type CreateSelfACPOptions = ACPScopeOptions & {
199
+ type?: 'self';
200
+ issuer: string;
201
+ name?: string;
202
+ expiration?: number;
203
+ revokerData?: number;
204
+ revokerContract?: string;
205
+ };
206
+ type CreateSharingACPOptions = ACPScopeOptions & {
207
+ type?: 'sharing';
208
+ issuer: string;
209
+ recipient: string;
210
+ name?: string;
211
+ expiration?: number;
212
+ revokerData?: number;
213
+ revokerContract?: string;
214
+ };
215
+ type ImportSharedACPOptions = ACPScopeOptions & {
216
+ type?: 'sharing';
217
+ issuer: string;
218
+ recipient: string;
219
+ issuerSignature: string;
220
+ name?: string;
221
+ expiration: number;
222
+ revokerData?: number;
223
+ revokerContract?: string;
224
+ };
225
+ /** An ACP is plain JSON-serializable data — the serialized form is the ACP itself. */
226
+ type SerializedACP = ACP;
227
+ /**
228
+ * The share payload produced by `ACPUtils.export()` — the full public component
229
+ * with `sealingKey`/`recipientSignature` left for the recipient to fill, plus
230
+ * the display name and acp type. Fixed shape: every field is always present
231
+ * (zero-values instead of omissions), so importers can parse a single schema.
232
+ * Mirrors the on-chain sharing payload struct field-for-field.
233
+ */
234
+ type SharedACP = Expand<Omit<ACPPublic, 'sealingKey' | 'recipientSignature'> & {
235
+ name: string;
236
+ type: 'sharing';
237
+ }>;
238
+ /**
239
+ * A share read back from the on-chain ACPShareRegistry: the posted payload
240
+ * (SharedACP minus the client-side name/type) plus its registry id.
241
+ */
242
+ type IncomingShare = Expand<Omit<SharedACP, 'name' | 'type'> & {
243
+ shareId: Hex;
244
+ }>;
245
+ /**
246
+ * A type representing the acp fields that are used to generate the hash
247
+ */
248
+ type ACPHashFields = Pick<ACP, 'type' | 'issuer' | 'expiration' | 'recipient' | 'revokerData' | 'revokerContract' | 'scope' | 'contracts' | 'handles'>;
249
+ /**
250
+ * Validation result type
251
+ */
252
+ interface ValidationResult {
253
+ valid: boolean;
254
+ error: 'invalid-schema' | 'expired' | 'not-signed' | null;
255
+ }
256
+ /**
257
+ * Signature types for EIP712 signing
258
+ */
259
+ type ACPSignaturePrimaryType = 'ACPIssuerSelf' | 'ACPIssuerShared' | 'ACPRecipient';
260
+ type Expand<T> = T extends infer O ? {
261
+ [K in keyof O]: O[K];
262
+ } : never;
263
+
264
+ /**
265
+ * Main ACP utilities - functional approach for React compatibility
266
+ */
267
+ declare const ACPUtils: {
268
+ /**
269
+ * Create a self acp for personal use
270
+ */
271
+ createSelf: (options: CreateSelfACPOptions) => SelfACP;
272
+ /**
273
+ * Create a sharing acp to be shared with another user
274
+ */
275
+ createSharing: (options: CreateSharingACPOptions) => SharingACP;
276
+ /**
277
+ * Import a shared acp from various input formats
278
+ */
279
+ importShared: (options: ImportSharedACPOptions | string) => RecipientACP;
280
+ /**
281
+ * Sign an ACP with the provided wallet client
282
+ */
283
+ sign: <T extends ACP>(acp: T, publicClient: PublicClient, walletClient: WalletClient) => Promise<T>;
284
+ /**
285
+ * Create and sign a self acp in one operation
286
+ */
287
+ createSelfAndSign: (options: CreateSelfACPOptions, publicClient: PublicClient, walletClient: WalletClient) => Promise<SelfACP>;
288
+ /**
289
+ * Create and sign a sharing acp in one operation
290
+ */
291
+ createSharingAndSign: (options: CreateSharingACPOptions, publicClient: PublicClient, walletClient: WalletClient) => Promise<SharingACP>;
292
+ /**
293
+ * Import and sign a shared acp in one operation from various input formats
294
+ */
295
+ importSharedAndSign: (options: ImportSharedACPOptions | string, publicClient: PublicClient, walletClient: WalletClient) => Promise<RecipientACP>;
296
+ /**
297
+ * Deserialize an ACP from serialized data
298
+ */
299
+ deserialize: (data: SerializedACP) => ACP;
300
+ /**
301
+ * Serialize an ACP for storage
302
+ */
303
+ serialize: (acp: ACP) => SerializedACP;
304
+ /**
305
+ * Validate an ACP (schema-level validation)
306
+ */
307
+ validateSchema: (acp: ACP) => {
308
+ name: string;
309
+ type: "self" | "sharing" | "recipient";
310
+ issuer: `0x${string}`;
311
+ expiration: number;
312
+ recipient: `0x${string}`;
313
+ revokerData: number;
314
+ revokerContract: `0x${string}`;
315
+ scope: number;
316
+ contracts: `0x${string}`[];
317
+ handles: `0x${string}`[];
318
+ issuerSignature: `0x${string}`;
319
+ recipientSignature: `0x${string}`;
320
+ sealingPrivateKey?: string | undefined;
321
+ sealingKey?: string | undefined;
322
+ };
323
+ /**
324
+ * Validate an ACP (holistic validation).
325
+ *
326
+ * This validates:
327
+ * - ACP schema (shape + invariants)
328
+ * - ACP is signed
329
+ * - ACP is not expired
330
+ *
331
+ * For schema-only validation, use `validateSchema(acp)`.
332
+ */
333
+ validate: (acp: ACP) => {
334
+ name: string;
335
+ type: "self" | "sharing" | "recipient";
336
+ issuer: `0x${string}`;
337
+ expiration: number;
338
+ recipient: `0x${string}`;
339
+ revokerData: number;
340
+ revokerContract: `0x${string}`;
341
+ scope: number;
342
+ contracts: `0x${string}`[];
343
+ handles: `0x${string}`[];
344
+ issuerSignature: `0x${string}`;
345
+ recipientSignature: `0x${string}`;
346
+ sealingPrivateKey?: string | undefined;
347
+ sealingKey?: string | undefined;
348
+ };
349
+ /**
350
+ * Get the public component of an ACP — the signed struct sent on-chain / to the decryption backend.
351
+ * Strips the private component (hash, name, type, sealing pair).
352
+ */
353
+ getPublic: (acp: ACP, skipValidation?: boolean) => ACPPublic;
354
+ /**
355
+ * Get a stable hash for the acp (used as key in storage)
356
+ */
357
+ getHash: (acp: ACPHashFields) => string;
358
+ /**
359
+ * Export acp data for sharing (strips the private component).
360
+ * Fixed `SharedACP` shape — every field always present, aligned with
361
+ * `ACPPublic` and the on-chain sharing payload.
362
+ */
363
+ export: (acp: ACP) => string;
364
+ /**
365
+ * Unseal encrypted data using the acp's sealing key
366
+ */
367
+ unseal: (acp: ACP, ciphertext: EthEncryptedData) => bigint;
368
+ /**
369
+ * Check if acp is expired
370
+ */
371
+ isExpired: (acp: ACP) => boolean;
372
+ /**
373
+ * Check if acp is signed
374
+ */
375
+ isSigned: (acp: ACP) => boolean;
376
+ /**
377
+ * Check if acp is signed and not expired
378
+ */
379
+ isSignedAndNotExpired: (acp: ACP) => ValidationResult;
380
+ /**
381
+ * Assert that acp is signed and not expired
382
+ */
383
+ assertSignedAndNotExpired: (acp: ACP) => void;
384
+ isValid: (acp: ACP) => ValidationResult;
385
+ /**
386
+ * Update acp name (returns new acp instance)
387
+ */
388
+ updateName: (acp: ACP, name: string) => ACP;
389
+ /**
390
+ * Fetch EIP712 domain from the blockchain
391
+ */
392
+ fetchEIP712Domain: (publicClient: PublicClient) => Promise<EIP712Domain>;
393
+ /**
394
+ * Check if acp's signed domain matches the provided domain
395
+ */
396
+ matchesDomain: (acp: ACP, domain: EIP712Domain) => boolean;
397
+ /**
398
+ * Check if acp's signed domain is valid for the current chain
399
+ */
400
+ checkSignedDomainValid: (acp: ACP, publicClient: PublicClient) => Promise<boolean>;
401
+ /**
402
+ * Check if acp passes the on-chain validation
403
+ */
404
+ checkValidityOnChain: (acp: ACP, publicClient: PublicClient) => Promise<boolean>;
405
+ };
406
+
407
+ export { type ACP as A, type CreateSelfACPOptions as C, type EIP712Types as E, GenerateSealingKey as G, type ImportSharedACPOptions as I, type RecipientACP as R, type SerializedACP as S, type ValidationResult as V, type ACPPublic as a, type ACPSignaturePrimaryType as b, type EIP712Message as c, type CreateSharingACPOptions as d, type ACPMetadata as e, type SharedACP as f, type IncomingShare as g, type EIP712Domain as h, ACPUtils as i, type SealingKeyPair as j, type EthEncryptedData as k, type EIP712Type as l, type ACPPrivate as m, type ACPType as n, type ACPOf as o, type SelfACP as p, type SharingACP as q, ACPScope as r, seal as s, type ACPScopeOptions as t, unsealWithPrivateKey as u, type ACPHashFields as v, type Expand as w };