@cofhe/sdk 0.8.0 → 1.0.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 (87) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/acps/acp.ts +25 -6
  3. package/acps/index.ts +20 -15
  4. package/acps/onchain-utils.ts +15 -10
  5. package/acps/registry.ts +166 -8
  6. package/acps/sealing.ts +31 -5
  7. package/acps/share-metadata/appKey.ts +8 -0
  8. package/acps/share-metadata/decode.ts +120 -0
  9. package/acps/share-metadata/describe.ts +198 -0
  10. package/acps/share-metadata/encode.ts +147 -0
  11. package/acps/share-metadata/erc7984.ts +26 -0
  12. package/acps/share-metadata/index.ts +9 -0
  13. package/acps/share-metadata/layout.ts +69 -0
  14. package/acps/share-metadata/presets.ts +116 -0
  15. package/acps/share-metadata/schema.ts +47 -0
  16. package/acps/share-metadata/test/codec.test.ts +140 -0
  17. package/acps/share-metadata/test/describe.test.ts +112 -0
  18. package/acps/share-metadata/test/fixtures.ts +157 -0
  19. package/acps/share-metadata/test/live.test.ts +56 -0
  20. package/acps/share-metadata/test/presets.test.ts +119 -0
  21. package/acps/share-metadata/test/verify.test.ts +144 -0
  22. package/acps/share-metadata/verify.ts +155 -0
  23. package/acps/store.ts +48 -18
  24. package/acps/test/aclServedAddresses.test.ts +65 -0
  25. package/acps/test/acp.test.ts +102 -7
  26. package/acps/test/localstorage.test.ts +28 -1
  27. package/acps/test/registry.test.ts +144 -0
  28. package/acps/test/sealing.test.ts +74 -0
  29. package/acps/test/store.test.ts +71 -0
  30. package/acps/test/utils.test.ts +63 -0
  31. package/acps/test/validation.test.ts +0 -4
  32. package/acps/types.ts +43 -6
  33. package/acps/utils.ts +15 -2
  34. package/acps/validation.ts +3 -1
  35. package/core/acps.ts +123 -74
  36. package/core/client.ts +33 -7
  37. package/core/clientTypes.ts +25 -7
  38. package/core/config.ts +8 -0
  39. package/core/decrypt/apiError.ts +4 -1
  40. package/core/decrypt/verifyDecryptResult.ts +4 -1
  41. package/core/encrypt/cofheMocksZkVerifySign.ts +19 -2
  42. package/core/test/acpDefaults.test.ts +108 -19
  43. package/core/test/acpStoreAccountCase.test.ts +80 -0
  44. package/core/test/acps.test.ts +38 -3
  45. package/core/test/apiError.test.ts +8 -0
  46. package/core/test/appKeyConfig.test.ts +94 -0
  47. package/core/test/config.test.ts +8 -0
  48. package/core/test/decryptBuilders.test.ts +110 -2
  49. package/core/test/incomingShares.test.ts +84 -0
  50. package/core/test/mocksEncryptRange.test.ts +90 -0
  51. package/core/test/utils.test.ts +128 -0
  52. package/core/test/verifyDecryptResult.test.ts +51 -0
  53. package/core/utils.ts +16 -9
  54. package/dist/acps.cjs +796 -132
  55. package/dist/acps.d.cts +367 -35
  56. package/dist/acps.d.ts +367 -35
  57. package/dist/acps.js +2 -2
  58. package/dist/{chunk-UJYOBHYA.js → chunk-3L2IVPMI.js} +688 -203
  59. package/dist/chunk-J23FYAI2.js +174 -0
  60. package/dist/{chunk-GGI7Y6AW.js → chunk-O2ITEUEU.js} +110 -269
  61. package/dist/chunk-WJGTPW7K.js +228 -0
  62. package/dist/{clientTypes-D3aIXmUp.d.cts → clientTypes-IO6b5Um8.d.cts} +61 -21
  63. package/dist/{clientTypes-5YPPR16m.d.ts → clientTypes-b1pOxOUE.d.ts} +61 -21
  64. package/dist/core.cjs +3115 -2584
  65. package/dist/core.d.cts +6 -3
  66. package/dist/core.d.ts +6 -3
  67. package/dist/core.js +4 -3
  68. package/dist/node.cjs +3001 -2470
  69. package/dist/node.d.cts +2 -2
  70. package/dist/node.d.ts +2 -2
  71. package/dist/node.js +18 -17
  72. package/dist/{onchain-utils-CUAK8glx.d.cts → onchain-utils-CgOslubH.d.cts} +139 -15
  73. package/dist/{onchain-utils-CUAK8glx.d.ts → onchain-utils-CgOslubH.d.ts} +139 -15
  74. package/dist/web.cjs +3011 -2487
  75. package/dist/web.d.cts +2 -2
  76. package/dist/web.d.ts +2 -2
  77. package/dist/web.js +4 -10
  78. package/dist/zkProve.worker.cjs +14 -7
  79. package/dist/zkProve.worker.js +2 -8
  80. package/node/index.ts +1 -10
  81. package/node/storage.ts +18 -7
  82. package/node/test/storage-permissions.test.ts +40 -0
  83. package/package.json +4 -4
  84. package/web/index.ts +1 -10
  85. package/web/test/threadPoolBenchHelper.ts +1 -7
  86. package/web/zkProve.worker.ts +1 -10
  87. package/dist/chunk-NMKMCAI3.js +0 -14
package/dist/acps.cjs CHANGED
@@ -14,9 +14,14 @@ var nacl__default = /*#__PURE__*/_interopDefault(nacl);
14
14
  // acps/acp.ts
15
15
 
16
16
  // acps/utils.ts
17
+ var HEX_BODY_REGEX = /^[0-9a-fA-F]*$/;
17
18
  var fromHexString = (hexString) => {
18
- const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
19
- const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
19
+ const body = hexString.replace(/^0x/, "");
20
+ if (!HEX_BODY_REGEX.test(body)) {
21
+ throw new Error("Invalid hex string: contains non-hexadecimal characters");
22
+ }
23
+ const padded = body.length % 2 === 1 ? `0${body}` : body;
24
+ const arr = padded.match(/.{1,2}/g);
20
25
  if (!arr)
21
26
  return new Uint8Array();
22
27
  return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
@@ -61,6 +66,100 @@ function isBigIntOrNumber(value) {
61
66
  }
62
67
  }
63
68
 
69
+ // core/error.ts
70
+ var CofheError = class _CofheError extends Error {
71
+ code;
72
+ cause;
73
+ hint;
74
+ context;
75
+ apiErrorCode;
76
+ constructor({ code, message, cause, hint, context, apiErrorCode }) {
77
+ const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
78
+ super(fullMessage);
79
+ this.name = "CofheError";
80
+ this.code = code;
81
+ this.cause = cause;
82
+ this.hint = hint;
83
+ this.context = context;
84
+ this.apiErrorCode = apiErrorCode;
85
+ if (Error.captureStackTrace) {
86
+ Error.captureStackTrace(this, _CofheError);
87
+ }
88
+ }
89
+ /**
90
+ * Creates a CofheError from an unknown error
91
+ * If the error is a CofheError, it is returned unchanged, else a new CofheError is created
92
+ * If a wrapperError is provided, it is used to create the new CofheError, else a default is used
93
+ */
94
+ static fromError(error, wrapperError) {
95
+ if (isCofheError(error))
96
+ return error;
97
+ const cause = error instanceof Error ? error : new Error(`${error}`);
98
+ return new _CofheError({
99
+ code: wrapperError?.code ?? "INTERNAL_ERROR" /* InternalError */,
100
+ message: wrapperError?.message ?? "An internal error occurred",
101
+ hint: wrapperError?.hint,
102
+ context: wrapperError?.context,
103
+ apiErrorCode: wrapperError?.apiErrorCode,
104
+ cause
105
+ });
106
+ }
107
+ /**
108
+ * Serializes the error to JSON string with proper handling of Error objects
109
+ */
110
+ serialize() {
111
+ return bigintSafeJsonStringify({
112
+ name: this.name,
113
+ code: this.code,
114
+ message: this.message,
115
+ hint: this.hint,
116
+ context: this.context,
117
+ apiErrorCode: this.apiErrorCode,
118
+ cause: this.cause ? {
119
+ name: this.cause.name,
120
+ message: this.cause.message,
121
+ stack: this.cause.stack
122
+ } : void 0,
123
+ stack: this.stack
124
+ });
125
+ }
126
+ /**
127
+ * Returns a human-readable string representation of the error
128
+ */
129
+ toString() {
130
+ const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
131
+ const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
132
+ if (this.hint) {
133
+ parts.push(`Hint: ${this.hint}`);
134
+ }
135
+ if (this.context && Object.keys(this.context).length > 0) {
136
+ parts.push(`Context: ${bigintSafeJsonStringify(this.context)}`);
137
+ }
138
+ if (this.stack) {
139
+ parts.push(`
140
+ Stack trace:`);
141
+ parts.push(this.stack);
142
+ }
143
+ if (this.cause) {
144
+ parts.push(`
145
+ Caused by: ${this.cause.name}: ${this.cause.message}`);
146
+ if (this.cause.stack) {
147
+ parts.push(this.cause.stack);
148
+ }
149
+ }
150
+ return parts.join("\n");
151
+ }
152
+ };
153
+ var bigintSafeJsonStringify = (value) => {
154
+ return JSON.stringify(value, (key, value2) => {
155
+ if (typeof value2 === "bigint") {
156
+ return `${value2}n`;
157
+ }
158
+ return value2;
159
+ });
160
+ };
161
+ var isCofheError = (error) => error instanceof CofheError;
162
+
64
163
  // acps/sealing.ts
65
164
  var KEY_HEX_LENGTH = 64;
66
165
  var GenerateSealingKey = () => {
@@ -73,7 +172,7 @@ var GenerateSealingKey = () => {
73
172
  var seal = (value, publicKey) => {
74
173
  isString(publicKey);
75
174
  isBigIntOrNumber(value);
76
- assertKeyLength(publicKey, "Public");
175
+ assertSealingKey(publicKey, "Public");
77
176
  const ephemeralKeyPair = nacl__default.default.box.keyPair();
78
177
  const nonce = nacl__default.default.randomBytes(nacl__default.default.box.nonceLength);
79
178
  const encryptedMessage = nacl__default.default.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
@@ -84,21 +183,40 @@ var seal = (value, publicKey) => {
84
183
  };
85
184
  };
86
185
  var unsealWithPrivateKey = (privateKey, parsedData) => {
87
- assertKeyLength(privateKey, "Private");
186
+ assertSealingKey(privateKey, "Private");
88
187
  const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
89
188
  const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
90
189
  const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
91
- const decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, fromHexString(privateKey));
190
+ let decryptedMessage;
191
+ let cause;
192
+ try {
193
+ decryptedMessage = nacl__default.default.box.open(dataToDecrypt, nonce, ephemPublicKey, fromHexString(privateKey));
194
+ } catch (e) {
195
+ decryptedMessage = null;
196
+ cause = e instanceof Error ? e : void 0;
197
+ }
92
198
  if (!decryptedMessage) {
93
- throw new Error("Failed to decrypt message");
199
+ throw new CofheError({
200
+ code: "SEAL_OUTPUT_FAILED" /* SealOutputFailed */,
201
+ message: "Failed to unseal decrypt response",
202
+ cause,
203
+ context: {
204
+ dataLength: dataToDecrypt.length,
205
+ nonceLength: nonce.length,
206
+ publicKeyLength: ephemPublicKey.length
207
+ }
208
+ });
94
209
  }
95
210
  return toBigInt(decryptedMessage);
96
211
  };
97
- var assertKeyLength = (key, kind) => {
212
+ var assertSealingKey = (key, kind) => {
98
213
  const bare = key.startsWith("0x") ? key.slice(2) : key;
99
214
  if (bare.length !== KEY_HEX_LENGTH) {
100
215
  throw new Error(`${kind} key must be of length ${KEY_HEX_LENGTH}`);
101
216
  }
217
+ if (!/^[0-9a-fA-F]+$/.test(bare)) {
218
+ throw new Error(`${kind} key must contain only hex characters`);
219
+ }
102
220
  };
103
221
  var ACPScope = {
104
222
  Global: 0,
@@ -151,7 +269,8 @@ var zACPWithDefaults = zod.z.object({
151
269
  contracts: contractsSchema,
152
270
  handles: handlesSchema,
153
271
  issuerSignature: bytesSchema.optional().default("0x"),
154
- recipientSignature: bytesSchema.optional().default("0x")
272
+ recipientSignature: bytesSchema.optional().default("0x"),
273
+ metadata: bytesSchema.optional()
155
274
  });
156
275
  var zACPWithSealingKeys = zACPWithDefaults.extend({
157
276
  /** X25519 private key, 0x-prefixed 32-byte hex; never leaves the client */
@@ -222,7 +341,6 @@ var ImportACPOptionsValidator = zod.z.object({
222
341
  type: zod.z.literal("recipient").optional().default("recipient"),
223
342
  issuer: addressNotZeroSchema,
224
343
  recipient: addressNotZeroSchema,
225
- name: zod.z.string().optional().default("Unnamed ACP"),
226
344
  expiration: zod.z.int(),
227
345
  revokerData: zod.z.int().optional().default(0),
228
346
  revokerContract: addressSchema.optional().default(viem.zeroAddress),
@@ -230,7 +348,9 @@ var ImportACPOptionsValidator = zod.z.object({
230
348
  contracts: contractsSchema,
231
349
  handles: handlesSchema,
232
350
  issuerSignature: bytesNotEmptySchema,
233
- recipientSignature: bytesSchema.optional().default("0x")
351
+ recipientSignature: bytesSchema.optional().default("0x"),
352
+ /** The share metadata (labels blob); `0x` means none and is dropped */
353
+ metadata: bytesSchema.optional().transform((val) => val === "0x" ? void 0 : val)
234
354
  }).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
235
355
  var ImportACPValidator = zACPWithSealingKeys.refine((data) => data.type === "recipient", {
236
356
  error: "Type must be 'recipient'"
@@ -402,100 +522,6 @@ var COFHE_ADDRESS_BOOK_ADDRESS = "0xC0F4e00E531a2B086492Ae3DCC1515038307196b";
402
522
  var TASK_MANAGER_ID = 1n;
403
523
  BigInt(1 << 30);
404
524
 
405
- // core/error.ts
406
- var CofheError = class _CofheError extends Error {
407
- code;
408
- cause;
409
- hint;
410
- context;
411
- apiErrorCode;
412
- constructor({ code, message, cause, hint, context, apiErrorCode }) {
413
- const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
414
- super(fullMessage);
415
- this.name = "CofheError";
416
- this.code = code;
417
- this.cause = cause;
418
- this.hint = hint;
419
- this.context = context;
420
- this.apiErrorCode = apiErrorCode;
421
- if (Error.captureStackTrace) {
422
- Error.captureStackTrace(this, _CofheError);
423
- }
424
- }
425
- /**
426
- * Creates a CofheError from an unknown error
427
- * If the error is a CofheError, it is returned unchanged, else a new CofheError is created
428
- * If a wrapperError is provided, it is used to create the new CofheError, else a default is used
429
- */
430
- static fromError(error, wrapperError) {
431
- if (isCofheError(error))
432
- return error;
433
- const cause = error instanceof Error ? error : new Error(`${error}`);
434
- return new _CofheError({
435
- code: wrapperError?.code ?? "INTERNAL_ERROR" /* InternalError */,
436
- message: wrapperError?.message ?? "An internal error occurred",
437
- hint: wrapperError?.hint,
438
- context: wrapperError?.context,
439
- apiErrorCode: wrapperError?.apiErrorCode,
440
- cause
441
- });
442
- }
443
- /**
444
- * Serializes the error to JSON string with proper handling of Error objects
445
- */
446
- serialize() {
447
- return bigintSafeJsonStringify({
448
- name: this.name,
449
- code: this.code,
450
- message: this.message,
451
- hint: this.hint,
452
- context: this.context,
453
- apiErrorCode: this.apiErrorCode,
454
- cause: this.cause ? {
455
- name: this.cause.name,
456
- message: this.cause.message,
457
- stack: this.cause.stack
458
- } : void 0,
459
- stack: this.stack
460
- });
461
- }
462
- /**
463
- * Returns a human-readable string representation of the error
464
- */
465
- toString() {
466
- const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
467
- const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
468
- if (this.hint) {
469
- parts.push(`Hint: ${this.hint}`);
470
- }
471
- if (this.context && Object.keys(this.context).length > 0) {
472
- parts.push(`Context: ${bigintSafeJsonStringify(this.context)}`);
473
- }
474
- if (this.stack) {
475
- parts.push(`
476
- Stack trace:`);
477
- parts.push(this.stack);
478
- }
479
- if (this.cause) {
480
- parts.push(`
481
- Caused by: ${this.cause.name}: ${this.cause.message}`);
482
- if (this.cause.stack) {
483
- parts.push(this.cause.stack);
484
- }
485
- }
486
- return parts.join("\n");
487
- }
488
- };
489
- var bigintSafeJsonStringify = (value) => {
490
- return JSON.stringify(value, (key, value2) => {
491
- if (typeof value2 === "bigint") {
492
- return `${value2}n`;
493
- }
494
- return value2;
495
- });
496
- };
497
- var isCofheError = (error) => error instanceof CofheError;
498
-
499
525
  // core/taskManager.ts
500
526
  var ADDRESS_BOOK_ABI = viem.parseAbi([
501
527
  "function getTm(uint256 id) view returns (address)",
@@ -803,19 +829,229 @@ var getAclServedAddresses = async (publicClient, chainId) => {
803
829
  } catch {
804
830
  return {};
805
831
  }
832
+ let transient = false;
833
+ const readServedAddress = (functionName) => publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName }).catch((err) => {
834
+ if (revertErrorName(err, ACL_SERVED_ADDRESSES_ABI) === void 0)
835
+ transient = true;
836
+ return void 0;
837
+ });
806
838
  const [defaultRevoker, shareRegistry] = await Promise.all([
807
- publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "defaultRevokerContract" }).catch(() => void 0),
808
- publicClient.readContract({ address: aclAddress, abi: ACL_SERVED_ADDRESSES_ABI, functionName: "shareRegistry" }).catch(() => void 0)
839
+ readServedAddress("defaultRevokerContract"),
840
+ readServedAddress("shareRegistry")
809
841
  ]);
810
842
  const resolved = {
811
843
  defaultRevoker: defaultRevoker != null && defaultRevoker !== viem.zeroAddress ? defaultRevoker : void 0,
812
844
  shareRegistry: shareRegistry != null && shareRegistry !== viem.zeroAddress ? shareRegistry : void 0
813
845
  };
814
- aclServedAddressesCache.set(chainId, resolved);
846
+ if (!transient)
847
+ aclServedAddressesCache.set(chainId, resolved);
815
848
  return resolved;
816
849
  };
817
850
 
851
+ // acps/share-metadata/layout.ts
852
+ var LAYOUT_VERSION = 3;
853
+ var ENTRY_KIND = {
854
+ stored: 0,
855
+ event: 1,
856
+ unlabelled: 255
857
+ };
858
+ var ARGS_CODE = {
859
+ none: 0,
860
+ issuer: 1,
861
+ explicit: 255
862
+ };
863
+ var ARG_TAG = {
864
+ word: 0,
865
+ issuer: 1
866
+ };
867
+ var APP_KEY_TAG = 1;
868
+ var BYTE_WIDTH = {
869
+ version: 1,
870
+ /** Length of a list, and a position in it: at most 255 of each per share. */
871
+ count: 1,
872
+ index: 1,
873
+ address: 20,
874
+ selector: 4,
875
+ /** uint32: 4.29 billion blocks. */
876
+ block: 4,
877
+ /** uint16: the position of a transaction within its block. */
878
+ txIndex: 2,
879
+ /** uint16: the block-wide position of a log (a busy block passes 255 logs). */
880
+ logIndex: 2,
881
+ kind: 1,
882
+ argsCode: 1,
883
+ returnWord: 1,
884
+ argTag: 1,
885
+ word: 32
886
+ };
887
+
888
+ // acps/share-metadata/encode.ts
889
+ var uint = (value, width) => viem.numberToHex(value, { size: width });
890
+ var BYTES_FIELD = {
891
+ contract: { width: BYTE_WIDTH.address, name: "a contract address" },
892
+ selector: { width: BYTE_WIDTH.selector, name: "a selector" },
893
+ viewCallArgument: { width: BYTE_WIDTH.word, name: "a view call argument" },
894
+ appKey: { width: BYTE_WIDTH.word, name: "an app key" }
895
+ };
896
+ var bytesField = (field, value) => {
897
+ const { width, name } = BYTES_FIELD[field];
898
+ if (!viem.isHex(value, { strict: true }) || viem.size(value) !== width) {
899
+ throw new Error(`share metadata: ${name} must be ${width} bytes`);
900
+ }
901
+ return value.toLowerCase();
902
+ };
903
+ var listOf = (keyOf, what) => {
904
+ const items = [];
905
+ const positions = /* @__PURE__ */ new Map();
906
+ const insert = (item) => {
907
+ const key = keyOf(item);
908
+ if (positions.has(key))
909
+ return;
910
+ positions.set(key, items.length);
911
+ items.push(item);
912
+ };
913
+ const positionOf = (item) => {
914
+ const position = positions.get(keyOf(item));
915
+ if (position === void 0)
916
+ throw new Error(`share metadata: ${what} ${keyOf(item)} was not collected`);
917
+ return position;
918
+ };
919
+ return { items, insert, positionOf };
920
+ };
921
+ var keyOfContract = (contract) => contract.toLowerCase();
922
+ var keyOfSelector = (selector) => selector.toLowerCase();
923
+ var keyOfTransaction = ({ block, txIndex }) => `${block}:${txIndex}`;
924
+ var transactionOf = ({ block, txIndex }) => ({ block, txIndex });
925
+ var encodeArg = (arg) => {
926
+ if (arg.type === "issuer")
927
+ return uint(ARG_TAG.issuer, BYTE_WIDTH.argTag);
928
+ return viem.concatHex([uint(ARG_TAG.word, BYTE_WIDTH.argTag), bytesField("viewCallArgument", arg.value)]);
929
+ };
930
+ var issuerWordOf = (issuer) => issuer == null ? void 0 : viem.padHex(issuer, { size: BYTE_WIDTH.word }).toLowerCase();
931
+ var asIssuer = (arg, issuerWord) => arg.type === "word" && issuerWord != null && arg.value.toLowerCase() === issuerWord ? { type: "issuer" } : arg;
932
+ var encodeArgs = ({ args: given, returnWord }, issuerWord) => {
933
+ const args = given.map((arg) => asIssuer(arg, issuerWord));
934
+ if (returnWord === 0 && args.length === 0)
935
+ return uint(ARGS_CODE.none, BYTE_WIDTH.argsCode);
936
+ if (returnWord === 0 && args.length === 1 && args[0].type === "issuer") {
937
+ return uint(ARGS_CODE.issuer, BYTE_WIDTH.argsCode);
938
+ }
939
+ return viem.concatHex([
940
+ uint(ARGS_CODE.explicit, BYTE_WIDTH.argsCode),
941
+ uint(returnWord, BYTE_WIDTH.returnWord),
942
+ uint(args.length, BYTE_WIDTH.count),
943
+ ...args.map(encodeArg)
944
+ ]);
945
+ };
946
+ var encodeShareMetadata = (labels, { issuer, appKey } = {}) => {
947
+ const issuerWord = issuerWordOf(issuer);
948
+ const contracts = listOf(keyOfContract, "contract");
949
+ const selectors = listOf(keyOfSelector, "selector");
950
+ const transactions = listOf(keyOfTransaction, "transaction");
951
+ for (const label of labels) {
952
+ if (label.kind === "unlabelled")
953
+ continue;
954
+ contracts.insert(label.contract);
955
+ selectors.insert(label.selector);
956
+ if (label.kind === "event")
957
+ transactions.insert(transactionOf(label));
958
+ }
959
+ const entries = labels.map((label) => {
960
+ switch (label.kind) {
961
+ case "stored":
962
+ return viem.concatHex([
963
+ uint(ENTRY_KIND.stored, BYTE_WIDTH.kind),
964
+ uint(contracts.positionOf(label.contract), BYTE_WIDTH.index),
965
+ uint(selectors.positionOf(label.selector), BYTE_WIDTH.index),
966
+ uint(label.block, BYTE_WIDTH.block),
967
+ encodeArgs(label, issuerWord)
968
+ ]);
969
+ case "event":
970
+ return viem.concatHex([
971
+ uint(ENTRY_KIND.event, BYTE_WIDTH.kind),
972
+ uint(contracts.positionOf(label.contract), BYTE_WIDTH.index),
973
+ uint(transactions.positionOf(transactionOf(label)), BYTE_WIDTH.index),
974
+ uint(label.logIndex, BYTE_WIDTH.logIndex),
975
+ uint(selectors.positionOf(label.selector), BYTE_WIDTH.index)
976
+ ]);
977
+ case "unlabelled":
978
+ return uint(ENTRY_KIND.unlabelled, BYTE_WIDTH.kind);
979
+ }
980
+ });
981
+ return viem.concatHex([
982
+ uint(LAYOUT_VERSION, BYTE_WIDTH.version),
983
+ uint(contracts.items.length, BYTE_WIDTH.count),
984
+ ...contracts.items.map((contract) => bytesField("contract", contract)),
985
+ uint(selectors.items.length, BYTE_WIDTH.count),
986
+ ...selectors.items.map((selector) => bytesField("selector", selector)),
987
+ uint(transactions.items.length, BYTE_WIDTH.count),
988
+ ...transactions.items.map(
989
+ (tx) => viem.concatHex([uint(tx.block, BYTE_WIDTH.block), uint(tx.txIndex, BYTE_WIDTH.txIndex)])
990
+ ),
991
+ ...entries,
992
+ ...appKey == null ? [] : [uint(APP_KEY_TAG, BYTE_WIDTH.count), bytesField("appKey", appKey)]
993
+ ]);
994
+ };
995
+ var findViewFunction = (abi, name, arity) => {
996
+ const named = abi.filter((item) => item.type === "function" && item.name === name);
997
+ if (named.length === 0)
998
+ throw new Error(`share metadata: the ABI has no function ${name}`);
999
+ const fitting = named.filter((fn2) => fn2.inputs.length === arity);
1000
+ if (fitting.length !== 1) {
1001
+ throw new Error(
1002
+ named.length === 1 ? `share metadata: ${name} takes ${named[0].inputs.length} arguments, ${arity} given` : `share metadata: no single overload of ${name} takes ${arity} arguments`
1003
+ );
1004
+ }
1005
+ const [fn] = fitting;
1006
+ if (fn.stateMutability !== "view" && fn.stateMutability !== "pure") {
1007
+ throw new Error(`share metadata: ${name} is not a view function`);
1008
+ }
1009
+ return fn;
1010
+ };
1011
+ var encodeReadArg = (fn, index, value) => {
1012
+ const input = fn.inputs[index];
1013
+ const word = viem.encodeAbiParameters([input], [value]);
1014
+ if (viem.size(word) !== BYTE_WIDTH.word) {
1015
+ throw new Error(
1016
+ `share metadata: argument ${index} of ${fn.name} is ${input.type}; only arguments of one static 32-byte word can be labelled`
1017
+ );
1018
+ }
1019
+ return { type: "word", value: word };
1020
+ };
1021
+ var viewFunctionLabel = (options) => {
1022
+ const { contract, block, returnWord = 0 } = options;
1023
+ const values = options.args ?? [];
1024
+ const fn = findViewFunction(options.abi, options.functionName, values.length);
1025
+ return {
1026
+ kind: "stored",
1027
+ contract,
1028
+ selector: viem.toFunctionSelector(fn),
1029
+ args: values.map((value, i) => encodeReadArg(fn, i, value)),
1030
+ returnWord,
1031
+ block
1032
+ };
1033
+ };
1034
+ var eventLogLabel = (log) => {
1035
+ const { address, blockNumber, transactionIndex, logIndex, topics } = log;
1036
+ const topic0 = topics[0];
1037
+ if (blockNumber == null || transactionIndex == null || logIndex == null) {
1038
+ throw new Error("share metadata: a pending log has no position to label");
1039
+ }
1040
+ if (topic0 == null || viem.size(topic0) !== 32)
1041
+ throw new Error("share metadata: an anonymous log has no event selector");
1042
+ return {
1043
+ kind: "event",
1044
+ contract: address,
1045
+ block: blockNumber,
1046
+ txIndex: transactionIndex,
1047
+ logIndex,
1048
+ selector: viem.sliceHex(topic0, 0, 4)
1049
+ };
1050
+ };
1051
+ var UNLABELLED = { kind: "unlabelled" };
1052
+
818
1053
  // acps/acp.ts
1054
+ var sharedByName = (issuer) => `Shared by ${issuer.slice(0, 6)}\u2026${issuer.slice(-4)}`;
819
1055
  var ACPUtils = {
820
1056
  /**
821
1057
  * Create a self acp for personal use
@@ -837,10 +1073,16 @@ var ACPUtils = {
837
1073
  */
838
1074
  createSharing: (options) => {
839
1075
  const validation = validateSharingACPOptions(options);
1076
+ const { labels, appKey } = options;
1077
+ if (labels != null && labels.length !== validation.handles.length) {
1078
+ throw new Error(`Cannot label a share of ${validation.handles.length} handles with ${labels.length} labels`);
1079
+ }
1080
+ const metadata = labels != null || appKey != null ? encodeShareMetadata(labels ?? validation.handles.map(() => UNLABELLED), { issuer: validation.issuer, appKey }) : void 0;
840
1081
  const sealingPair = GenerateSealingKey();
841
1082
  const acp = {
842
1083
  hash: ACPUtils.getHash(validation),
843
1084
  ...validation,
1085
+ ...metadata != null && { metadata },
844
1086
  sealingPrivateKey: sealingPair.privateKey,
845
1087
  sealingKey: sealingPair.publicKey,
846
1088
  _signedDomain: void 0
@@ -848,9 +1090,10 @@ var ACPUtils = {
848
1090
  return acp;
849
1091
  },
850
1092
  /**
851
- * Import a shared acp from various input formats
1093
+ * Import a shared acp from various input formats. The acp is named `name`, or after its issuer
1094
+ * ("Shared by 0x1234…abcd"); a `name` in the share itself is ignored.
852
1095
  */
853
- importShared: (options) => {
1096
+ importShared: (options, { name } = {}) => {
854
1097
  let parsedOptions;
855
1098
  if (typeof options === "string") {
856
1099
  try {
@@ -871,6 +1114,7 @@ var ACPUtils = {
871
1114
  const acp = {
872
1115
  hash: ACPUtils.getHash(validation),
873
1116
  ...validation,
1117
+ name: name?.trim() || sharedByName(validation.issuer),
874
1118
  sealingPrivateKey: sealingPair.privateKey,
875
1119
  sealingKey: sealingPair.publicKey,
876
1120
  _signedDomain: void 0
@@ -929,8 +1173,8 @@ var ACPUtils = {
929
1173
  /**
930
1174
  * Import and sign a shared acp in one operation from various input formats
931
1175
  */
932
- importSharedAndSign: async (options, publicClient, walletClient) => {
933
- const acp = ACPUtils.importShared(options);
1176
+ importSharedAndSign: async (options, publicClient, walletClient, importOptions = {}) => {
1177
+ const acp = ACPUtils.importShared(options, importOptions);
934
1178
  return ACPUtils.sign(acp, publicClient, walletClient);
935
1179
  },
936
1180
  /**
@@ -959,7 +1203,8 @@ var ACPUtils = {
959
1203
  issuerSignature: acp.issuerSignature,
960
1204
  recipientSignature: acp.recipientSignature,
961
1205
  _signedDomain: acp._signedDomain,
962
- sealingPrivateKey: acp.sealingPrivateKey
1206
+ sealingPrivateKey: acp.sealingPrivateKey,
1207
+ ...acp.metadata != null && { metadata: acp.metadata }
963
1208
  };
964
1209
  },
965
1210
  /**
@@ -1033,7 +1278,7 @@ var ACPUtils = {
1033
1278
  /**
1034
1279
  * Export acp data for sharing (strips the private component).
1035
1280
  * Fixed `SharedACP` shape — every field always present, aligned with
1036
- * `ACPPublic` and the on-chain sharing payload.
1281
+ * `ACPPublic` and the on-chain sharing payload — plus `metadata` when the acp has labels.
1037
1282
  */
1038
1283
  export: (acp) => {
1039
1284
  if (acp.type !== "sharing") {
@@ -1047,7 +1292,6 @@ var ACPUtils = {
1047
1292
  );
1048
1293
  }
1049
1294
  const shared = {
1050
- name: acp.name,
1051
1295
  type: acp.type,
1052
1296
  issuer: acp.issuer,
1053
1297
  expiration: acp.expiration,
@@ -1057,7 +1301,8 @@ var ACPUtils = {
1057
1301
  scope: acp.scope,
1058
1302
  contracts: acp.contracts,
1059
1303
  handles: acp.handles,
1060
- issuerSignature: acp.issuerSignature
1304
+ issuerSignature: acp.issuerSignature,
1305
+ ...acp.metadata != null && acp.metadata !== "0x" && { metadata: acp.metadata }
1061
1306
  };
1062
1307
  return JSON.stringify(shared, void 0, 2);
1063
1308
  },
@@ -1143,11 +1388,14 @@ var ACP_REVOKER_ABI = viem.parseAbi([
1143
1388
  ]);
1144
1389
  var ACP_SHARE_REGISTRY_ABI = viem.parseAbi([
1145
1390
  "struct ACP { address issuer; uint64 expiration; address recipient; uint256 revokerData; address revokerContract; uint8 scope; address[] contracts; bytes32[] handles; bytes32 sealingKey; bytes issuerSignature; bytes recipientSignature; }",
1146
- "function share(ACP calldata acp) external returns (bytes32)",
1391
+ "struct ShareHeader { address issuer; uint64 expiration; address recipient; uint64 blockNumber; address revokerContract; uint256 revokerData; }",
1392
+ "function share(ACP calldata acp, bytes calldata metadata) external returns (bytes32)",
1147
1393
  "function removeShare(bytes32 shareId) external",
1148
- "function sharesFor(address recipient) external view returns (ACP[] memory)",
1149
- "function getShare(bytes32 shareId) external view returns (ACP memory)",
1150
- "function isShareValid(bytes32 shareId) external view returns (bool)"
1394
+ "function sharesFor(address recipient) external view returns (bytes32[] shareIds, ShareHeader[] headers)",
1395
+ "function getShare(bytes32 shareId) external view returns (ShareHeader memory)",
1396
+ "function isShareValid(bytes32 shareId) external view returns (bool)",
1397
+ "event Shared(address indexed recipient, address indexed issuer, bytes32 indexed shareId, ACP acp, bytes metadata)",
1398
+ "event ShareRemoved(address indexed recipient, address indexed issuer, bytes32 indexed shareId)"
1151
1399
  ]);
1152
1400
  var ACP_SHARE_TUPLE_ABI = [
1153
1401
  {
@@ -1183,11 +1431,393 @@ var computeShareId = (acp) => {
1183
1431
  return viem.keccak256(viem.encodeAbiParameters(ACP_SHARE_TUPLE_ABI, [p]));
1184
1432
  };
1185
1433
  var shareIdOfChainShare = (share) => viem.keccak256(viem.encodeAbiParameters(ACP_SHARE_TUPLE_ABI, [share]));
1434
+ var messageOf = (error) => error instanceof Error ? error.message : String(error);
1435
+ var readPostedShares = async (publicClient, registry, headers) => {
1436
+ const idsByBlock = /* @__PURE__ */ new Map();
1437
+ for (const { shareId, header } of headers) {
1438
+ idsByBlock.set(header.blockNumber, [...idsByBlock.get(header.blockNumber) ?? [], shareId]);
1439
+ }
1440
+ const found = /* @__PURE__ */ new Map();
1441
+ await Promise.all(
1442
+ [...idsByBlock].map(async ([block, shareIds]) => {
1443
+ let logs;
1444
+ try {
1445
+ logs = await publicClient.getContractEvents({
1446
+ address: registry,
1447
+ abi: ACP_SHARE_REGISTRY_ABI,
1448
+ eventName: "Shared",
1449
+ args: { shareId: shareIds },
1450
+ fromBlock: block,
1451
+ toBlock: block,
1452
+ strict: true
1453
+ });
1454
+ } catch (error) {
1455
+ for (const shareId of shareIds) {
1456
+ found.set(shareId.toLowerCase(), {
1457
+ reason: `the Shared events of block ${block} could not be read: ${messageOf(error)}`
1458
+ });
1459
+ }
1460
+ return;
1461
+ }
1462
+ for (const { args } of logs) {
1463
+ const hashes = shareIdOfChainShare(args.acp).toLowerCase() === args.shareId.toLowerCase();
1464
+ found.set(
1465
+ args.shareId.toLowerCase(),
1466
+ hashes ? { share: args.acp, metadata: args.metadata } : { reason: "the payload in its Shared event does not hash to its id" }
1467
+ );
1468
+ }
1469
+ })
1470
+ );
1471
+ const result = { posted: [], unreadable: [] };
1472
+ for (const { shareId, header } of headers) {
1473
+ const entry = found.get(shareId.toLowerCase());
1474
+ if (entry == null) {
1475
+ result.unreadable.push({
1476
+ shareId,
1477
+ header,
1478
+ reason: `no Shared event in block ${header.blockNumber}, where the registry points`
1479
+ });
1480
+ } else if ("reason" in entry) {
1481
+ result.unreadable.push({ shareId, header, reason: entry.reason });
1482
+ } else {
1483
+ result.posted.push({ shareId, header, ...entry });
1484
+ }
1485
+ }
1486
+ return result;
1487
+ };
1488
+ var readSharesFor = async (publicClient, registry, recipient) => {
1489
+ const [shareIds, headers] = await publicClient.readContract({
1490
+ address: registry,
1491
+ abi: ACP_SHARE_REGISTRY_ABI,
1492
+ functionName: "sharesFor",
1493
+ args: [recipient]
1494
+ });
1495
+ return readPostedShares(
1496
+ publicClient,
1497
+ registry,
1498
+ shareIds.map((shareId, i) => ({ shareId, header: headers[i] }))
1499
+ );
1500
+ };
1501
+ var readShare = async (publicClient, registry, shareId) => {
1502
+ const header = await publicClient.readContract({
1503
+ address: registry,
1504
+ abi: ACP_SHARE_REGISTRY_ABI,
1505
+ functionName: "getShare",
1506
+ args: [shareId]
1507
+ });
1508
+ if (header.issuer === "0x0000000000000000000000000000000000000000")
1509
+ return null;
1510
+ const { posted, unreadable } = await readPostedShares(publicClient, registry, [{ shareId, header }]);
1511
+ if (unreadable.length > 0)
1512
+ throw new Error(`Share ${shareId}: ${unreadable[0].reason}`);
1513
+ return posted[0];
1514
+ };
1515
+ var readerOf = (blob) => {
1516
+ let offset = 0;
1517
+ const take = (width) => {
1518
+ if (offset + width > viem.size(blob))
1519
+ throw new Error("share metadata: the blob ends in the middle of a field");
1520
+ offset += width;
1521
+ return viem.sliceHex(blob, offset - width, offset);
1522
+ };
1523
+ return {
1524
+ take,
1525
+ takeNumber: (width) => viem.hexToNumber(take(width)),
1526
+ done: () => offset === viem.size(blob),
1527
+ remaining: () => viem.size(blob) - offset
1528
+ };
1529
+ };
1530
+ var takeList = (reader, takeItem) => Array.from({ length: reader.takeNumber(BYTE_WIDTH.count) }, takeItem);
1531
+ var takeFrom = (reader, list, what) => {
1532
+ const position = reader.takeNumber(BYTE_WIDTH.index);
1533
+ if (position >= list.length) {
1534
+ throw new Error(`share metadata: ${what} ${position} is outside the ${what} list`);
1535
+ }
1536
+ return list[position];
1537
+ };
1538
+ var decodeArg = (reader) => {
1539
+ const tag = reader.takeNumber(BYTE_WIDTH.argTag);
1540
+ if (tag === ARG_TAG.issuer)
1541
+ return { type: "issuer" };
1542
+ if (tag === ARG_TAG.word)
1543
+ return { type: "word", value: reader.take(BYTE_WIDTH.word) };
1544
+ throw new Error(`share metadata: unknown argument tag ${tag}`);
1545
+ };
1546
+ var decodeArgs = (reader) => {
1547
+ const code = reader.takeNumber(BYTE_WIDTH.argsCode);
1548
+ if (code === ARGS_CODE.none)
1549
+ return { args: [], returnWord: 0 };
1550
+ if (code === ARGS_CODE.issuer)
1551
+ return { args: [{ type: "issuer" }], returnWord: 0 };
1552
+ if (code !== ARGS_CODE.explicit)
1553
+ throw new Error(`share metadata: unknown args code ${code}`);
1554
+ const returnWord = reader.takeNumber(BYTE_WIDTH.returnWord);
1555
+ return { args: takeList(reader, () => decodeArg(reader)), returnWord };
1556
+ };
1557
+ var takeAppKey = (reader) => {
1558
+ if (reader.done())
1559
+ return void 0;
1560
+ const isKey = reader.remaining() === BYTE_WIDTH.count + BYTE_WIDTH.word && reader.takeNumber(BYTE_WIDTH.count) === APP_KEY_TAG;
1561
+ if (!isKey)
1562
+ throw new Error("share metadata: the blob has more entries than the share has ctHashes");
1563
+ return reader.take(BYTE_WIDTH.word);
1564
+ };
1565
+ var decodeShareMetadataFull = (blob, handles) => {
1566
+ const reader = readerOf(blob);
1567
+ const version = reader.takeNumber(BYTE_WIDTH.version);
1568
+ if (version !== LAYOUT_VERSION)
1569
+ throw new Error(`share metadata: unsupported version ${version}`);
1570
+ const contracts = takeList(reader, () => viem.getAddress(reader.take(BYTE_WIDTH.address)));
1571
+ const selectors = takeList(reader, () => reader.take(BYTE_WIDTH.selector));
1572
+ const transactions = takeList(reader, () => ({
1573
+ block: viem.hexToBigInt(reader.take(BYTE_WIDTH.block)),
1574
+ txIndex: reader.takeNumber(BYTE_WIDTH.txIndex)
1575
+ }));
1576
+ const labels = handles.map(() => {
1577
+ const kind = reader.takeNumber(BYTE_WIDTH.kind);
1578
+ switch (kind) {
1579
+ case ENTRY_KIND.stored: {
1580
+ const contract = takeFrom(reader, contracts, "contract");
1581
+ const selector = takeFrom(reader, selectors, "selector");
1582
+ const block = viem.hexToBigInt(reader.take(BYTE_WIDTH.block));
1583
+ return { kind: "stored", contract, selector, ...decodeArgs(reader), block };
1584
+ }
1585
+ case ENTRY_KIND.event: {
1586
+ const contract = takeFrom(reader, contracts, "contract");
1587
+ const { block, txIndex } = takeFrom(reader, transactions, "transaction");
1588
+ const logIndex = reader.takeNumber(BYTE_WIDTH.logIndex);
1589
+ const selector = takeFrom(reader, selectors, "selector");
1590
+ return { kind: "event", contract, block, txIndex, logIndex, selector };
1591
+ }
1592
+ case ENTRY_KIND.unlabelled:
1593
+ return { kind: "unlabelled" };
1594
+ default:
1595
+ throw new Error(`share metadata: unknown entry kind ${kind}`);
1596
+ }
1597
+ });
1598
+ const appKey = takeAppKey(reader);
1599
+ if (!reader.done())
1600
+ throw new Error("share metadata: the blob has more entries than the share has ctHashes");
1601
+ return { labels, appKey };
1602
+ };
1603
+ var decodeShareMetadata = (blob, handles) => decodeShareMetadataFull(blob, handles).labels;
1604
+ var decodeShareAppKey = (metadata, handles) => metadata == null || metadata === "0x" ? void 0 : decodeShareMetadataFull(metadata, handles).appKey;
1605
+ var sameWord = (a, b) => a.toLowerCase() === b.toLowerCase();
1606
+ var wordsOf = (data) => {
1607
+ const count = Math.floor(viem.size(data) / BYTE_WIDTH.word);
1608
+ return Array.from(
1609
+ { length: count },
1610
+ (_, index) => viem.sliceHex(data, index * BYTE_WIDTH.word, (index + 1) * BYTE_WIDTH.word)
1611
+ );
1612
+ };
1613
+ var storedCallData = (label, issuer) => viem.concatHex([
1614
+ label.selector,
1615
+ ...label.args.map((arg) => arg.type === "issuer" ? viem.padHex(issuer, { size: BYTE_WIDTH.word }) : arg.value)
1616
+ ]);
1617
+ var checkStored = (label, handle, data) => {
1618
+ const found = data ? wordsOf(data)[label.returnWord] : void 0;
1619
+ return found && sameWord(found, handle) ? "verified" : "mismatch";
1620
+ };
1621
+ var checkEvent = (label, handle, logs) => {
1622
+ const log = logs.find((l) => l.logIndex === label.logIndex);
1623
+ if (log == null)
1624
+ return "mismatch";
1625
+ if (log.transactionIndex !== label.txIndex)
1626
+ return "mismatch";
1627
+ const topic0 = log.topics[0];
1628
+ if (topic0 == null || !topic0.toLowerCase().startsWith(label.selector.toLowerCase()))
1629
+ return "mismatch";
1630
+ const carried = [...log.topics.slice(1), ...wordsOf(log.data)].some((word) => word != null && sameWord(word, handle));
1631
+ return carried ? "verified" : "mismatch";
1632
+ };
1633
+ var callAt = async (publicClient, to, data, blockNumber) => (await publicClient.call({ to, data, blockNumber })).data;
1634
+ var logsAt = (publicClient, address, block) => publicClient.getLogs({ address, fromBlock: block, toBlock: block });
1635
+ var verifyShareLabel = async (label, handle, publicClient, issuer) => {
1636
+ try {
1637
+ switch (label.kind) {
1638
+ case "stored":
1639
+ return checkStored(
1640
+ label,
1641
+ handle,
1642
+ await callAt(publicClient, label.contract, storedCallData(label, issuer), label.block)
1643
+ );
1644
+ case "event":
1645
+ return checkEvent(label, handle, await logsAt(publicClient, label.contract, label.block));
1646
+ case "unlabelled":
1647
+ return "unverifiable";
1648
+ }
1649
+ } catch {
1650
+ return "unverifiable";
1651
+ }
1652
+ };
1653
+ var verifyShareLabels = async ({
1654
+ labels,
1655
+ handles,
1656
+ issuer,
1657
+ publicClient,
1658
+ verify = "all"
1659
+ }) => {
1660
+ if (labels.length !== handles.length) {
1661
+ throw new Error(`share metadata: ${labels.length} labels for ${handles.length} ctHashes`);
1662
+ }
1663
+ const requests = /* @__PURE__ */ new Map();
1664
+ const once = (key, request) => {
1665
+ if (!requests.has(key))
1666
+ requests.set(key, request());
1667
+ return requests.get(key);
1668
+ };
1669
+ return Promise.all(
1670
+ labels.map(async (label, i) => {
1671
+ const handle = handles[i];
1672
+ try {
1673
+ switch (label.kind) {
1674
+ case "stored": {
1675
+ if (verify !== "all")
1676
+ return "skipped";
1677
+ const data = storedCallData(label, issuer);
1678
+ const key = `call:${label.contract.toLowerCase()}:${label.block}:${data}`;
1679
+ return checkStored(
1680
+ label,
1681
+ handle,
1682
+ await once(key, () => callAt(publicClient, label.contract, data, label.block))
1683
+ );
1684
+ }
1685
+ case "event": {
1686
+ if (verify === "none")
1687
+ return "skipped";
1688
+ const key = `logs:${label.contract.toLowerCase()}:${label.block}`;
1689
+ return checkEvent(label, handle, await once(key, () => logsAt(publicClient, label.contract, label.block)));
1690
+ }
1691
+ case "unlabelled":
1692
+ return verify === "none" ? "skipped" : "unverifiable";
1693
+ }
1694
+ } catch {
1695
+ return "unverifiable";
1696
+ }
1697
+ })
1698
+ );
1699
+ };
1700
+ var abiOf = (abis, contract) => {
1701
+ const wanted = contract.toLowerCase();
1702
+ const key = Object.keys(abis).find((address) => address.toLowerCase() === wanted);
1703
+ return key ? abis[key] : void 0;
1704
+ };
1705
+ var paramOf = ({ name, type, ...rest }) => {
1706
+ const param = { type };
1707
+ if (name)
1708
+ param.name = name;
1709
+ if ("indexed" in rest && typeof rest.indexed === "boolean")
1710
+ param.indexed = rest.indexed;
1711
+ return param;
1712
+ };
1713
+ var findFunction = (abi, selector) => abi?.find(
1714
+ (item) => item.type === "function" && viem.toFunctionSelector(item).toLowerCase() === selector.toLowerCase()
1715
+ );
1716
+ var findEvent = (abi, selector) => abi?.find(
1717
+ (item) => item.type === "event" && viem.toEventSelector(item).toLowerCase().startsWith(selector.toLowerCase())
1718
+ );
1719
+ var decodeWord = (input, raw) => {
1720
+ if (input == null)
1721
+ return raw;
1722
+ try {
1723
+ return viem.decodeAbiParameters([input], raw)[0];
1724
+ } catch {
1725
+ return raw;
1726
+ }
1727
+ };
1728
+ var describeStored = (base, label, abis, issuer) => {
1729
+ const fn = findFunction(abiOf(abis, label.contract), label.selector);
1730
+ const args = label.args.map((arg, i) => {
1731
+ const input = fn?.inputs[i];
1732
+ const param = input ? paramOf(input) : { type: "bytes32" };
1733
+ if (arg.type === "issuer") {
1734
+ return {
1735
+ ...param,
1736
+ isIssuer: true,
1737
+ raw: issuer ? viem.padHex(issuer, { size: 32 }) : void 0,
1738
+ value: issuer
1739
+ };
1740
+ }
1741
+ return { ...param, isIssuer: false, raw: arg.value, value: decodeWord(input, arg.value) };
1742
+ });
1743
+ const output = fn?.outputs[label.returnWord];
1744
+ return {
1745
+ ...base,
1746
+ kind: "stored",
1747
+ label,
1748
+ contract: label.contract,
1749
+ block: label.block,
1750
+ selector: label.selector,
1751
+ function: fn ? { name: fn.name, signature: viem.toFunctionSignature(fn), inputs: fn.inputs.map(paramOf) } : null,
1752
+ args,
1753
+ output: output ? paramOf(output) : null
1754
+ };
1755
+ };
1756
+ var describeEvent = (base, label, abis) => {
1757
+ const event = findEvent(abiOf(abis, label.contract), label.selector);
1758
+ return {
1759
+ ...base,
1760
+ kind: "event",
1761
+ label,
1762
+ contract: label.contract,
1763
+ block: label.block,
1764
+ txIndex: label.txIndex,
1765
+ logIndex: label.logIndex,
1766
+ selector: label.selector,
1767
+ event: event ? { name: event.name, signature: viem.toEventSignature(event), inputs: event.inputs.map(paramOf) } : null
1768
+ };
1769
+ };
1770
+ var describeShareLabels = (labels, handles, abis = {}, options = {}) => labels.map((label, index) => {
1771
+ const base = { index, handle: handles[index] };
1772
+ switch (label.kind) {
1773
+ case "stored":
1774
+ return describeStored(base, label, abis, options.issuer);
1775
+ case "event":
1776
+ return describeEvent(base, label, abis);
1777
+ case "unlabelled":
1778
+ return { ...base, kind: "unlabelled", label };
1779
+ }
1780
+ });
1781
+ var describeShareMetadata = (share, abis = {}) => {
1782
+ const { issuer, handles, metadata } = share;
1783
+ if (metadata == null || metadata === "0x")
1784
+ return null;
1785
+ return describeShareLabels(decodeShareMetadata(metadata, handles), handles, abis, { issuer });
1786
+ };
1787
+
1788
+ // acps/share-metadata/erc7984.ts
1789
+ var ERC7984_ABI = [
1790
+ {
1791
+ type: "function",
1792
+ name: "confidentialBalanceOf",
1793
+ stateMutability: "view",
1794
+ inputs: [{ name: "account", type: "address", internalType: "address" }],
1795
+ outputs: [{ name: "", type: "bytes32", internalType: "euint64" }]
1796
+ },
1797
+ {
1798
+ type: "event",
1799
+ name: "ConfidentialTransfer",
1800
+ anonymous: false,
1801
+ inputs: [
1802
+ { name: "from", type: "address", indexed: true, internalType: "address" },
1803
+ { name: "to", type: "address", indexed: true, internalType: "address" },
1804
+ { name: "amount", type: "bytes32", indexed: true, internalType: "euint64" }
1805
+ ]
1806
+ }
1807
+ ];
1808
+ var shareAppKey = (app) => viem.keccak256(viem.stringToHex(app));
1186
1809
  var ACP_STORE_DEFAULTS = {
1187
1810
  acps: {},
1188
1811
  activeACPHash: {}
1189
1812
  };
1190
1813
  var ACP_STORE_VERSION = 3;
1814
+ var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
1815
+ var resolveAccountKey = (records, account) => {
1816
+ if (records == null || account in records)
1817
+ return account;
1818
+ const lower = account.toLowerCase();
1819
+ return Object.keys(records).find((key) => key.toLowerCase() === lower) ?? account;
1820
+ };
1191
1821
  var _acpStore = vanilla.createStore()(
1192
1822
  middleware.persist(() => ACP_STORE_DEFAULTS, {
1193
1823
  name: "cofhesdk-acps",
@@ -1196,12 +1826,23 @@ var _acpStore = vanilla.createStore()(
1196
1826
  if (version < ACP_STORE_VERSION)
1197
1827
  return ACP_STORE_DEFAULTS;
1198
1828
  return persistedState;
1829
+ },
1830
+ // Runs on every rehydrate, including a corrupt state saved at the current version that
1831
+ // `migrate` passes through unchanged. Consumers that read the raw snapshot (e.g. the React
1832
+ // hooks) never go through `clearStaleStore`, so the shape has to be fixed here.
1833
+ merge: (persistedState, currentState) => {
1834
+ const persisted = isRecord(persistedState) ? persistedState : {};
1835
+ return {
1836
+ ...currentState,
1837
+ acps: isRecord(persisted.acps) ? persisted.acps : currentState.acps,
1838
+ activeACPHash: isRecord(persisted.activeACPHash) ? persisted.activeACPHash : currentState.activeACPHash
1839
+ };
1199
1840
  }
1200
1841
  })
1201
1842
  );
1202
1843
  var clearStaleStore = () => {
1203
1844
  const state = _acpStore.getState();
1204
- const hasExpectedStructure = state && typeof state === "object" && "acps" in state && "activeACPHash" in state && typeof state.acps === "object" && typeof state.activeACPHash === "object";
1845
+ const hasExpectedStructure = isRecord(state) && isRecord(state.acps) && isRecord(state.activeACPHash);
1205
1846
  if (hasExpectedStructure)
1206
1847
  return;
1207
1848
  _acpStore.setState({ acps: {}, activeACPHash: {} });
@@ -1210,7 +1851,8 @@ var getACP = (chainId, account, hash) => {
1210
1851
  clearStaleStore();
1211
1852
  if (chainId == null || account == null || hash == null)
1212
1853
  return;
1213
- const savedACP = _acpStore.getState().acps[chainId]?.[account]?.[hash];
1854
+ const accountACPs = _acpStore.getState().acps[chainId];
1855
+ const savedACP = accountACPs?.[resolveAccountKey(accountACPs, account)]?.[hash];
1214
1856
  if (savedACP == null)
1215
1857
  return;
1216
1858
  return ACPUtils.deserialize(savedACP);
@@ -1219,14 +1861,16 @@ var getActiveACP = (chainId, account) => {
1219
1861
  clearStaleStore();
1220
1862
  if (chainId == null || account == null)
1221
1863
  return;
1222
- const activeACPHash = _acpStore.getState().activeACPHash[chainId]?.[account];
1864
+ const activeHashes = _acpStore.getState().activeACPHash[chainId];
1865
+ const activeACPHash = activeHashes?.[resolveAccountKey(activeHashes, account)];
1223
1866
  return getACP(chainId, account, activeACPHash);
1224
1867
  };
1225
1868
  var getACPs = (chainId, account) => {
1226
1869
  clearStaleStore();
1227
1870
  if (chainId == null || account == null)
1228
1871
  return {};
1229
- return Object.entries(_acpStore.getState().acps[chainId]?.[account] ?? {}).reduce(
1872
+ const accountACPs = _acpStore.getState().acps[chainId];
1873
+ return Object.entries(accountACPs?.[resolveAccountKey(accountACPs, account)] ?? {}).reduce(
1230
1874
  (acc, [hash, acp]) => {
1231
1875
  if (acp == void 0)
1232
1876
  return acc;
@@ -1241,9 +1885,10 @@ var setACP = (chainId, account, acp) => {
1241
1885
  immer.produce((state) => {
1242
1886
  if (state.acps[chainId] == null)
1243
1887
  state.acps[chainId] = {};
1244
- if (state.acps[chainId][account] == null)
1245
- state.acps[chainId][account] = {};
1246
- state.acps[chainId][account][acp.hash] = ACPUtils.serialize(acp);
1888
+ const key = resolveAccountKey(state.acps[chainId], account);
1889
+ if (state.acps[chainId][key] == null)
1890
+ state.acps[chainId][key] = {};
1891
+ state.acps[chainId][key][acp.hash] = ACPUtils.serialize(acp);
1247
1892
  })
1248
1893
  );
1249
1894
  };
@@ -1255,13 +1900,14 @@ var removeACP = (chainId, account, hash) => {
1255
1900
  state.acps[chainId] = {};
1256
1901
  if (state.activeACPHash[chainId] == null)
1257
1902
  state.activeACPHash[chainId] = {};
1258
- const accountACPs = state.acps[chainId][account];
1903
+ const accountACPs = state.acps[chainId][resolveAccountKey(state.acps[chainId], account)];
1259
1904
  if (accountACPs == null)
1260
1905
  return;
1261
1906
  if (accountACPs[hash] == null)
1262
1907
  return;
1263
- if (state.activeACPHash[chainId][account] === hash) {
1264
- state.activeACPHash[chainId][account] = void 0;
1908
+ const activeKey = resolveAccountKey(state.activeACPHash[chainId], account);
1909
+ if (state.activeACPHash[chainId][activeKey] === hash) {
1910
+ state.activeACPHash[chainId][activeKey] = void 0;
1265
1911
  }
1266
1912
  accountACPs[hash] = void 0;
1267
1913
  })
@@ -1271,7 +1917,8 @@ var getActiveACPHash = (chainId, account) => {
1271
1917
  clearStaleStore();
1272
1918
  if (chainId == null || account == null)
1273
1919
  return void 0;
1274
- return _acpStore.getState().activeACPHash[chainId]?.[account];
1920
+ const activeHashes = _acpStore.getState().activeACPHash[chainId];
1921
+ return activeHashes?.[resolveAccountKey(activeHashes, account)];
1275
1922
  };
1276
1923
  var setActiveACPHash = (chainId, account, hash) => {
1277
1924
  clearStaleStore();
@@ -1279,7 +1926,7 @@ var setActiveACPHash = (chainId, account, hash) => {
1279
1926
  immer.produce((state) => {
1280
1927
  if (state.activeACPHash[chainId] == null)
1281
1928
  state.activeACPHash[chainId] = {};
1282
- state.activeACPHash[chainId][account] = hash;
1929
+ state.activeACPHash[chainId][resolveAccountKey(state.activeACPHash[chainId], account)] = hash;
1283
1930
  })
1284
1931
  );
1285
1932
  };
@@ -1288,7 +1935,7 @@ var removeActiveACPHash = (chainId, account) => {
1288
1935
  _acpStore.setState(
1289
1936
  immer.produce((state) => {
1290
1937
  if (state.activeACPHash[chainId])
1291
- state.activeACPHash[chainId][account] = void 0;
1938
+ state.activeACPHash[chainId][resolveAccountKey(state.activeACPHash[chainId], account)] = void 0;
1292
1939
  })
1293
1940
  );
1294
1941
  };
@@ -1315,15 +1962,18 @@ exports.ACP_REVOKER_ABI = ACP_REVOKER_ABI;
1315
1962
  exports.ACP_SHARE_REGISTRY_ABI = ACP_SHARE_REGISTRY_ABI;
1316
1963
  exports.ACP_SHARE_TUPLE_ABI = ACP_SHARE_TUPLE_ABI;
1317
1964
  exports.ACP_STORE_DEFAULTS = ACP_STORE_DEFAULTS;
1965
+ exports.ERC7984_ABI = ERC7984_ABI;
1318
1966
  exports.GenerateSealingKey = GenerateSealingKey;
1319
1967
  exports.ImportACPOptionsValidator = ImportACPOptionsValidator;
1320
1968
  exports.ImportACPValidator = ImportACPValidator;
1969
+ exports.SHARE_METADATA_VERSION = LAYOUT_VERSION;
1321
1970
  exports.SelfACPOptionsValidator = SelfACPOptionsValidator;
1322
1971
  exports.SelfACPValidator = SelfACPValidator;
1323
1972
  exports.SharingACPOptionsValidator = SharingACPOptionsValidator;
1324
1973
  exports.SharingACPValidator = SharingACPValidator;
1325
1974
  exports.SignatureTypes = SignatureTypes;
1326
1975
  exports.SignatureUtils = SignatureUtils;
1976
+ exports.UNLABELLED = UNLABELLED;
1327
1977
  exports.ValidationUtils = ValidationUtils;
1328
1978
  exports._acpStore = _acpStore;
1329
1979
  exports.acpStore = acpStore;
@@ -1335,6 +1985,13 @@ exports.clearAclServedAddresses = clearAclServedAddresses;
1335
1985
  exports.clearStaleStore = clearStaleStore;
1336
1986
  exports.computeShareId = computeShareId;
1337
1987
  exports.contractsSchema = contractsSchema;
1988
+ exports.decodeShareAppKey = decodeShareAppKey;
1989
+ exports.decodeShareMetadata = decodeShareMetadata;
1990
+ exports.decodeShareMetadataFull = decodeShareMetadataFull;
1991
+ exports.describeShareLabels = describeShareLabels;
1992
+ exports.describeShareMetadata = describeShareMetadata;
1993
+ exports.encodeShareMetadata = encodeShareMetadata;
1994
+ exports.eventLogLabel = eventLogLabel;
1338
1995
  exports.getACP = getACP;
1339
1996
  exports.getACPs = getACPs;
1340
1997
  exports.getAclAddress = getAclAddress;
@@ -1343,12 +2000,16 @@ exports.getActiveACP = getActiveACP;
1343
2000
  exports.getActiveACPHash = getActiveACPHash;
1344
2001
  exports.getSignatureTypesAndMessage = getSignatureTypesAndMessage;
1345
2002
  exports.handlesSchema = handlesSchema;
2003
+ exports.readPostedShares = readPostedShares;
2004
+ exports.readShare = readShare;
2005
+ exports.readSharesFor = readSharesFor;
1346
2006
  exports.removeACP = removeACP;
1347
2007
  exports.removeActiveACPHash = removeActiveACPHash;
1348
2008
  exports.resetStore = resetStore;
1349
2009
  exports.seal = seal;
1350
2010
  exports.setACP = setACP;
1351
2011
  exports.setActiveACPHash = setActiveACPHash;
2012
+ exports.shareAppKey = shareAppKey;
1352
2013
  exports.shareIdOfChainShare = shareIdOfChainShare;
1353
2014
  exports.toChainShare = toChainShare;
1354
2015
  exports.unsealWithPrivateKey = unsealWithPrivateKey;
@@ -1358,3 +2019,6 @@ exports.validateSelfACP = validateSelfACP;
1358
2019
  exports.validateSelfACPOptions = validateSelfACPOptions;
1359
2020
  exports.validateSharingACP = validateSharingACP;
1360
2021
  exports.validateSharingACPOptions = validateSharingACPOptions;
2022
+ exports.verifyShareLabel = verifyShareLabel;
2023
+ exports.verifyShareLabels = verifyShareLabels;
2024
+ exports.viewFunctionLabel = viewFunctionLabel;