@cofhe/sdk 0.8.0 → 1.0.0-alpha.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 (84) hide show
  1. package/acps/acp.ts +25 -6
  2. package/acps/index.ts +20 -15
  3. package/acps/registry.ts +166 -8
  4. package/acps/sealing.ts +9 -3
  5. package/acps/share-metadata/appKey.ts +8 -0
  6. package/acps/share-metadata/decode.ts +120 -0
  7. package/acps/share-metadata/describe.ts +198 -0
  8. package/acps/share-metadata/encode.ts +147 -0
  9. package/acps/share-metadata/erc7984.ts +26 -0
  10. package/acps/share-metadata/index.ts +9 -0
  11. package/acps/share-metadata/layout.ts +69 -0
  12. package/acps/share-metadata/presets.ts +116 -0
  13. package/acps/share-metadata/schema.ts +47 -0
  14. package/acps/share-metadata/test/codec.test.ts +140 -0
  15. package/acps/share-metadata/test/describe.test.ts +112 -0
  16. package/acps/share-metadata/test/fixtures.ts +157 -0
  17. package/acps/share-metadata/test/live.test.ts +56 -0
  18. package/acps/share-metadata/test/presets.test.ts +119 -0
  19. package/acps/share-metadata/test/verify.test.ts +144 -0
  20. package/acps/share-metadata/verify.ts +155 -0
  21. package/acps/store.ts +48 -18
  22. package/acps/test/acp.test.ts +102 -7
  23. package/acps/test/localstorage.test.ts +28 -1
  24. package/acps/test/registry.test.ts +144 -0
  25. package/acps/test/sealing.test.ts +23 -0
  26. package/acps/test/store.test.ts +71 -0
  27. package/acps/test/utils.test.ts +63 -0
  28. package/acps/test/validation.test.ts +0 -4
  29. package/acps/types.ts +43 -6
  30. package/acps/utils.ts +15 -2
  31. package/acps/validation.ts +3 -1
  32. package/core/acps.ts +123 -74
  33. package/core/client.ts +33 -7
  34. package/core/clientTypes.ts +25 -7
  35. package/core/config.ts +8 -0
  36. package/core/decrypt/apiError.ts +4 -1
  37. package/core/decrypt/verifyDecryptResult.ts +4 -1
  38. package/core/encrypt/cofheMocksZkVerifySign.ts +19 -2
  39. package/core/test/acpDefaults.test.ts +108 -19
  40. package/core/test/acpStoreAccountCase.test.ts +80 -0
  41. package/core/test/acps.test.ts +38 -3
  42. package/core/test/apiError.test.ts +8 -0
  43. package/core/test/appKeyConfig.test.ts +94 -0
  44. package/core/test/config.test.ts +8 -0
  45. package/core/test/decryptBuilders.test.ts +110 -2
  46. package/core/test/incomingShares.test.ts +84 -0
  47. package/core/test/mocksEncryptRange.test.ts +90 -0
  48. package/core/test/utils.test.ts +128 -0
  49. package/core/test/verifyDecryptResult.test.ts +51 -0
  50. package/core/utils.ts +16 -9
  51. package/dist/acps.cjs +674 -33
  52. package/dist/acps.d.cts +367 -35
  53. package/dist/acps.d.ts +367 -35
  54. package/dist/acps.js +2 -2
  55. package/dist/chunk-6ZW76ZKB.js +228 -0
  56. package/dist/{chunk-UJYOBHYA.js → chunk-BQWHPIYU.js} +660 -198
  57. package/dist/{chunk-GGI7Y6AW.js → chunk-OL3DZN7A.js} +110 -269
  58. package/dist/chunk-XQ32JG3T.js +174 -0
  59. package/dist/{clientTypes-D3aIXmUp.d.cts → clientTypes-C0A9ji5O.d.cts} +61 -21
  60. package/dist/{clientTypes-5YPPR16m.d.ts → clientTypes-CcU5WvdV.d.ts} +61 -21
  61. package/dist/core.cjs +3239 -2731
  62. package/dist/core.d.cts +6 -3
  63. package/dist/core.d.ts +6 -3
  64. package/dist/core.js +4 -3
  65. package/dist/node.cjs +3046 -2538
  66. package/dist/node.d.cts +2 -2
  67. package/dist/node.d.ts +2 -2
  68. package/dist/node.js +18 -17
  69. package/dist/{onchain-utils-CUAK8glx.d.cts → onchain-utils-D9Z33IP7.d.cts} +136 -12
  70. package/dist/{onchain-utils-CUAK8glx.d.ts → onchain-utils-D9Z33IP7.d.ts} +136 -12
  71. package/dist/web.cjs +3074 -2573
  72. package/dist/web.d.cts +2 -2
  73. package/dist/web.d.ts +2 -2
  74. package/dist/web.js +4 -10
  75. package/dist/zkProve.worker.cjs +14 -7
  76. package/dist/zkProve.worker.js +2 -8
  77. package/node/index.ts +1 -10
  78. package/node/storage.ts +18 -7
  79. package/node/test/storage-permissions.test.ts +40 -0
  80. package/package.json +4 -4
  81. package/web/index.ts +1 -10
  82. package/web/test/threadPoolBenchHelper.ts +1 -7
  83. package/web/zkProve.worker.ts +1 -10
  84. package/dist/chunk-NMKMCAI3.js +0 -14
@@ -1,5 +1,5 @@
1
- import { TASK_MANAGER_ID, COFHE_ADDRESS_BOOK_ADDRESS } from './chunk-NMKMCAI3.js';
2
- import { isAddress, getAddress, zeroAddress, isHex, parseAbi, keccak256, toHex, encodeAbiParameters, decodeErrorResult } from 'viem';
1
+ import { TASK_MANAGER_ID, COFHE_ADDRESS_BOOK_ADDRESS, CofheError } from './chunk-XQ32JG3T.js';
2
+ import { isAddress, getAddress, zeroAddress, isHex, parseAbi, keccak256, padHex, numberToHex, concatHex, toFunctionSelector, size, sliceHex, toHex, encodeAbiParameters, hexToBigInt, stringToHex, hexToNumber, toEventSignature, toFunctionSignature, decodeErrorResult, toEventSelector, decodeAbiParameters } from 'viem';
3
3
  import nacl from 'tweetnacl';
4
4
  import { z } from 'zod';
5
5
  import { createStore } from 'zustand/vanilla';
@@ -7,9 +7,14 @@ import { persist } from 'zustand/middleware';
7
7
  import { produce } from 'immer';
8
8
 
9
9
  // acps/utils.ts
10
+ var HEX_BODY_REGEX = /^[0-9a-fA-F]*$/;
10
11
  var fromHexString = (hexString) => {
11
- const cleanString = hexString.length % 2 === 1 ? `0${hexString}` : hexString;
12
- const arr = cleanString.replace(/^0x/, "").match(/.{1,2}/g);
12
+ const body = hexString.replace(/^0x/, "");
13
+ if (!HEX_BODY_REGEX.test(body)) {
14
+ throw new Error("Invalid hex string: contains non-hexadecimal characters");
15
+ }
16
+ const padded = body.length % 2 === 1 ? `0${body}` : body;
17
+ const arr = padded.match(/.{1,2}/g);
13
18
  if (!arr)
14
19
  return new Uint8Array();
15
20
  return new Uint8Array(arr.map((byte) => parseInt(byte, 16)));
@@ -66,7 +71,7 @@ var GenerateSealingKey = () => {
66
71
  var seal = (value, publicKey) => {
67
72
  isString(publicKey);
68
73
  isBigIntOrNumber(value);
69
- assertKeyLength(publicKey, "Public");
74
+ assertSealingKey(publicKey, "Public");
70
75
  const ephemeralKeyPair = nacl.box.keyPair();
71
76
  const nonce = nacl.randomBytes(nacl.box.nonceLength);
72
77
  const encryptedMessage = nacl.box(toBeArray(value), nonce, fromHexString(publicKey), ephemeralKeyPair.secretKey);
@@ -77,7 +82,7 @@ var seal = (value, publicKey) => {
77
82
  };
78
83
  };
79
84
  var unsealWithPrivateKey = (privateKey, parsedData) => {
80
- assertKeyLength(privateKey, "Private");
85
+ assertSealingKey(privateKey, "Private");
81
86
  const nonce = parsedData.nonce instanceof Uint8Array ? parsedData.nonce : new Uint8Array(parsedData.nonce);
82
87
  const ephemPublicKey = parsedData.public_key instanceof Uint8Array ? parsedData.public_key : new Uint8Array(parsedData.public_key);
83
88
  const dataToDecrypt = parsedData.data instanceof Uint8Array ? parsedData.data : new Uint8Array(parsedData.data);
@@ -87,11 +92,14 @@ var unsealWithPrivateKey = (privateKey, parsedData) => {
87
92
  }
88
93
  return toBigInt(decryptedMessage);
89
94
  };
90
- var assertKeyLength = (key, kind) => {
95
+ var assertSealingKey = (key, kind) => {
91
96
  const bare = key.startsWith("0x") ? key.slice(2) : key;
92
97
  if (bare.length !== KEY_HEX_LENGTH) {
93
98
  throw new Error(`${kind} key must be of length ${KEY_HEX_LENGTH}`);
94
99
  }
100
+ if (!/^[0-9a-fA-F]+$/.test(bare)) {
101
+ throw new Error(`${kind} key must contain only hex characters`);
102
+ }
95
103
  };
96
104
  var ACPScope = {
97
105
  Global: 0,
@@ -144,7 +152,8 @@ var zACPWithDefaults = z.object({
144
152
  contracts: contractsSchema,
145
153
  handles: handlesSchema,
146
154
  issuerSignature: bytesSchema.optional().default("0x"),
147
- recipientSignature: bytesSchema.optional().default("0x")
155
+ recipientSignature: bytesSchema.optional().default("0x"),
156
+ metadata: bytesSchema.optional()
148
157
  });
149
158
  var zACPWithSealingKeys = zACPWithDefaults.extend({
150
159
  /** X25519 private key, 0x-prefixed 32-byte hex; never leaves the client */
@@ -215,7 +224,6 @@ var ImportACPOptionsValidator = z.object({
215
224
  type: z.literal("recipient").optional().default("recipient"),
216
225
  issuer: addressNotZeroSchema,
217
226
  recipient: addressNotZeroSchema,
218
- name: z.string().optional().default("Unnamed ACP"),
219
227
  expiration: z.int(),
220
228
  revokerData: z.int().optional().default(0),
221
229
  revokerContract: addressSchema.optional().default(zeroAddress),
@@ -223,7 +231,9 @@ var ImportACPOptionsValidator = z.object({
223
231
  contracts: contractsSchema,
224
232
  handles: handlesSchema,
225
233
  issuerSignature: bytesNotEmptySchema,
226
- recipientSignature: bytesSchema.optional().default("0x")
234
+ recipientSignature: bytesSchema.optional().default("0x"),
235
+ /** The share metadata (labels blob); `0x` means none and is dropped */
236
+ metadata: bytesSchema.optional().transform((val) => val === "0x" ? void 0 : val)
227
237
  }).refine(...ExternalValidatorRefinement).transform(withDerivedScope).refine(...ScopeConsistencyRefinement);
228
238
  var ImportACPValidator = zACPWithSealingKeys.refine((data) => data.type === "recipient", {
229
239
  error: "Type must be 'recipient'"
@@ -389,168 +399,6 @@ var SignatureUtils = {
389
399
  throw new Error(`Unknown acp type: ${acpType}`);
390
400
  }
391
401
  };
392
-
393
- // core/error.ts
394
- var CofheErrorCode = /* @__PURE__ */ ((CofheErrorCode2) => {
395
- CofheErrorCode2["InternalError"] = "INTERNAL_ERROR";
396
- CofheErrorCode2["UnknownEnvironment"] = "UNKNOWN_ENVIRONMENT";
397
- CofheErrorCode2["InitTfheFailed"] = "INIT_TFHE_FAILED";
398
- CofheErrorCode2["InitViemFailed"] = "INIT_VIEM_FAILED";
399
- CofheErrorCode2["InitEthersFailed"] = "INIT_ETHERS_FAILED";
400
- CofheErrorCode2["NotConnected"] = "NOT_CONNECTED";
401
- CofheErrorCode2["MissingPublicClient"] = "MISSING_PUBLIC_CLIENT";
402
- CofheErrorCode2["MissingWalletClient"] = "MISSING_WALLET_CLIENT";
403
- CofheErrorCode2["MissingProviderParam"] = "MISSING_PROVIDER_PARAM";
404
- CofheErrorCode2["EmptySecurityZonesParam"] = "EMPTY_SECURITY_ZONES_PARAM";
405
- CofheErrorCode2["InvalidACPData"] = "INVALID_ACP_DATA";
406
- CofheErrorCode2["InvalidACPDomain"] = "INVALID_ACP_DOMAIN";
407
- CofheErrorCode2["ACPNotFound"] = "ACP_NOT_FOUND";
408
- CofheErrorCode2["CannotRemoveLastACP"] = "CANNOT_REMOVE_LAST_ACP";
409
- CofheErrorCode2["AccountUninitialized"] = "ACCOUNT_UNINITIALIZED";
410
- CofheErrorCode2["ChainIdUninitialized"] = "CHAIN_ID_UNINITIALIZED";
411
- CofheErrorCode2["ConsumingContractUninitialized"] = "CONSUMING_CONTRACT_UNINITIALIZED";
412
- CofheErrorCode2["SealOutputFailed"] = "SEAL_OUTPUT_FAILED";
413
- CofheErrorCode2["SealOutputReturnedNull"] = "SEAL_OUTPUT_RETURNED_NULL";
414
- CofheErrorCode2["InvalidUtype"] = "INVALID_UTYPE";
415
- CofheErrorCode2["DecryptFailed"] = "DECRYPT_FAILED";
416
- CofheErrorCode2["DecryptReturnedNull"] = "DECRYPT_RETURNED_NULL";
417
- CofheErrorCode2["ZkMocksInsertCtHashesFailed"] = "ZK_MOCKS_INSERT_CT_HASHES_FAILED";
418
- CofheErrorCode2["ZkMocksCalcCtHashesFailed"] = "ZK_MOCKS_CALC_CT_HASHES_FAILED";
419
- CofheErrorCode2["ZkMocksVerifySignFailed"] = "ZK_MOCKS_VERIFY_SIGN_FAILED";
420
- CofheErrorCode2["ZkMocksCreateProofSignatureFailed"] = "ZK_MOCKS_CREATE_PROOF_SIGNATURE_FAILED";
421
- CofheErrorCode2["ZkVerifyFailed"] = "ZK_VERIFY_FAILED";
422
- CofheErrorCode2["ZkPackFailed"] = "ZK_PACK_FAILED";
423
- CofheErrorCode2["ZkProveFailed"] = "ZK_PROVE_FAILED";
424
- CofheErrorCode2["EncryptRemainingInItems"] = "ENCRYPT_REMAINING_IN_ITEMS";
425
- CofheErrorCode2["ZkUninitialized"] = "ZK_UNINITIALIZED";
426
- CofheErrorCode2["ZkVerifierUrlUninitialized"] = "ZK_VERIFIER_URL_UNINITIALIZED";
427
- CofheErrorCode2["ThresholdNetworkUrlUninitialized"] = "THRESHOLD_NETWORK_URL_UNINITIALIZED";
428
- CofheErrorCode2["MissingConfig"] = "MISSING_CONFIG";
429
- CofheErrorCode2["UnsupportedChain"] = "UNSUPPORTED_CHAIN";
430
- CofheErrorCode2["MissingZkBuilderAndCrsGenerator"] = "MISSING_ZK_BUILDER_AND_CRS_GENERATOR";
431
- CofheErrorCode2["MissingTfhePublicKeyDeserializer"] = "MISSING_TFHE_PUBLIC_KEY_DESERIALIZER";
432
- CofheErrorCode2["MissingCompactPkeCrsDeserializer"] = "MISSING_COMPACT_PKE_CRS_DESERIALIZER";
433
- CofheErrorCode2["MissingFheKey"] = "MISSING_FHE_KEY";
434
- CofheErrorCode2["MissingCrs"] = "MISSING_CRS";
435
- CofheErrorCode2["FetchKeysFailed"] = "FETCH_KEYS_FAILED";
436
- CofheErrorCode2["PublicWalletGetChainIdFailed"] = "PUBLIC_WALLET_GET_CHAIN_ID_FAILED";
437
- CofheErrorCode2["PublicWalletGetAddressesFailed"] = "PUBLIC_WALLET_GET_ADDRESSES_FAILED";
438
- CofheErrorCode2["RehydrateKeysStoreFailed"] = "REHYDRATE_KEYS_STORE_FAILED";
439
- CofheErrorCode2["TaskManagerUnresolved"] = "TASK_MANAGER_UNRESOLVED";
440
- CofheErrorCode2["BadRequest"] = "BAD_REQUEST";
441
- CofheErrorCode2["UnknownChain"] = "UNKNOWN_CHAIN";
442
- CofheErrorCode2["ACPMalformed"] = "ACP_MALFORMED";
443
- CofheErrorCode2["ACPDenied"] = "ACP_DENIED";
444
- CofheErrorCode2["ACPExpired"] = "ACP_EXPIRED";
445
- CofheErrorCode2["ACPInvalid"] = "ACP_INVALID";
446
- CofheErrorCode2["ACPRevoked"] = "ACP_REVOKED";
447
- CofheErrorCode2["NotPubliclyAllowed"] = "NOT_PUBLICLY_ALLOWED";
448
- CofheErrorCode2["CtNotFound"] = "CT_NOT_FOUND";
449
- CofheErrorCode2["UnsupportedSecurityZone"] = "UNSUPPORTED_SECURITY_ZONE";
450
- CofheErrorCode2["UnsupportedType"] = "UNSUPPORTED_TYPE";
451
- CofheErrorCode2["SigningFailed"] = "SIGNING_FAILED";
452
- CofheErrorCode2["CtSourceError"] = "CT_SOURCE_ERROR";
453
- CofheErrorCode2["ACPVerifierError"] = "ACP_VERIFIER_ERROR";
454
- CofheErrorCode2["CtSourceTimeout"] = "CT_SOURCE_TIMEOUT";
455
- CofheErrorCode2["ACPVerifierTimeout"] = "ACP_VERIFIER_TIMEOUT";
456
- CofheErrorCode2["ACPRequired"] = "ACP_REQUIRED";
457
- CofheErrorCode2["SealFailed"] = "SEAL_FAILED";
458
- return CofheErrorCode2;
459
- })(CofheErrorCode || {});
460
- var CofheError = class _CofheError extends Error {
461
- code;
462
- cause;
463
- hint;
464
- context;
465
- apiErrorCode;
466
- constructor({ code, message, cause, hint, context, apiErrorCode }) {
467
- const fullMessage = cause ? `${message} | Caused by: ${cause.message}` : message;
468
- super(fullMessage);
469
- this.name = "CofheError";
470
- this.code = code;
471
- this.cause = cause;
472
- this.hint = hint;
473
- this.context = context;
474
- this.apiErrorCode = apiErrorCode;
475
- if (Error.captureStackTrace) {
476
- Error.captureStackTrace(this, _CofheError);
477
- }
478
- }
479
- /**
480
- * Creates a CofheError from an unknown error
481
- * If the error is a CofheError, it is returned unchanged, else a new CofheError is created
482
- * If a wrapperError is provided, it is used to create the new CofheError, else a default is used
483
- */
484
- static fromError(error, wrapperError) {
485
- if (isCofheError(error))
486
- return error;
487
- const cause = error instanceof Error ? error : new Error(`${error}`);
488
- return new _CofheError({
489
- code: wrapperError?.code ?? "INTERNAL_ERROR" /* InternalError */,
490
- message: wrapperError?.message ?? "An internal error occurred",
491
- hint: wrapperError?.hint,
492
- context: wrapperError?.context,
493
- apiErrorCode: wrapperError?.apiErrorCode,
494
- cause
495
- });
496
- }
497
- /**
498
- * Serializes the error to JSON string with proper handling of Error objects
499
- */
500
- serialize() {
501
- return bigintSafeJsonStringify({
502
- name: this.name,
503
- code: this.code,
504
- message: this.message,
505
- hint: this.hint,
506
- context: this.context,
507
- apiErrorCode: this.apiErrorCode,
508
- cause: this.cause ? {
509
- name: this.cause.name,
510
- message: this.cause.message,
511
- stack: this.cause.stack
512
- } : void 0,
513
- stack: this.stack
514
- });
515
- }
516
- /**
517
- * Returns a human-readable string representation of the error
518
- */
519
- toString() {
520
- const codeSuffix = this.apiErrorCode ? ` (api: ${this.apiErrorCode})` : "";
521
- const parts = [`${this.name} [${this.code}]${codeSuffix}: ${this.message}`];
522
- if (this.hint) {
523
- parts.push(`Hint: ${this.hint}`);
524
- }
525
- if (this.context && Object.keys(this.context).length > 0) {
526
- parts.push(`Context: ${bigintSafeJsonStringify(this.context)}`);
527
- }
528
- if (this.stack) {
529
- parts.push(`
530
- Stack trace:`);
531
- parts.push(this.stack);
532
- }
533
- if (this.cause) {
534
- parts.push(`
535
- Caused by: ${this.cause.name}: ${this.cause.message}`);
536
- if (this.cause.stack) {
537
- parts.push(this.cause.stack);
538
- }
539
- }
540
- return parts.join("\n");
541
- }
542
- };
543
- var bigintSafeJsonStringify = (value) => {
544
- return JSON.stringify(value, (key, value2) => {
545
- if (typeof value2 === "bigint") {
546
- return `${value2}n`;
547
- }
548
- return value2;
549
- });
550
- };
551
- var isCofheError = (error) => error instanceof CofheError;
552
-
553
- // core/taskManager.ts
554
402
  var ADDRESS_BOOK_ABI = parseAbi([
555
403
  "function getTm(uint256 id) view returns (address)",
556
404
  "error TaskManagerNotSet(uint256 id)"
@@ -869,7 +717,210 @@ var getAclServedAddresses = async (publicClient, chainId) => {
869
717
  return resolved;
870
718
  };
871
719
 
720
+ // acps/share-metadata/layout.ts
721
+ var LAYOUT_VERSION = 3;
722
+ var ENTRY_KIND = {
723
+ stored: 0,
724
+ event: 1,
725
+ unlabelled: 255
726
+ };
727
+ var ARGS_CODE = {
728
+ none: 0,
729
+ issuer: 1,
730
+ explicit: 255
731
+ };
732
+ var ARG_TAG = {
733
+ word: 0,
734
+ issuer: 1
735
+ };
736
+ var APP_KEY_TAG = 1;
737
+ var BYTE_WIDTH = {
738
+ version: 1,
739
+ /** Length of a list, and a position in it: at most 255 of each per share. */
740
+ count: 1,
741
+ index: 1,
742
+ address: 20,
743
+ selector: 4,
744
+ /** uint32: 4.29 billion blocks. */
745
+ block: 4,
746
+ /** uint16: the position of a transaction within its block. */
747
+ txIndex: 2,
748
+ /** uint16: the block-wide position of a log (a busy block passes 255 logs). */
749
+ logIndex: 2,
750
+ kind: 1,
751
+ argsCode: 1,
752
+ returnWord: 1,
753
+ argTag: 1,
754
+ word: 32
755
+ };
756
+
757
+ // acps/share-metadata/encode.ts
758
+ var uint = (value, width) => numberToHex(value, { size: width });
759
+ var BYTES_FIELD = {
760
+ contract: { width: BYTE_WIDTH.address, name: "a contract address" },
761
+ selector: { width: BYTE_WIDTH.selector, name: "a selector" },
762
+ viewCallArgument: { width: BYTE_WIDTH.word, name: "a view call argument" },
763
+ appKey: { width: BYTE_WIDTH.word, name: "an app key" }
764
+ };
765
+ var bytesField = (field, value) => {
766
+ const { width, name } = BYTES_FIELD[field];
767
+ if (!isHex(value, { strict: true }) || size(value) !== width) {
768
+ throw new Error(`share metadata: ${name} must be ${width} bytes`);
769
+ }
770
+ return value.toLowerCase();
771
+ };
772
+ var listOf = (keyOf, what) => {
773
+ const items = [];
774
+ const positions = /* @__PURE__ */ new Map();
775
+ const insert = (item) => {
776
+ const key = keyOf(item);
777
+ if (positions.has(key))
778
+ return;
779
+ positions.set(key, items.length);
780
+ items.push(item);
781
+ };
782
+ const positionOf = (item) => {
783
+ const position = positions.get(keyOf(item));
784
+ if (position === void 0)
785
+ throw new Error(`share metadata: ${what} ${keyOf(item)} was not collected`);
786
+ return position;
787
+ };
788
+ return { items, insert, positionOf };
789
+ };
790
+ var keyOfContract = (contract) => contract.toLowerCase();
791
+ var keyOfSelector = (selector) => selector.toLowerCase();
792
+ var keyOfTransaction = ({ block, txIndex }) => `${block}:${txIndex}`;
793
+ var transactionOf = ({ block, txIndex }) => ({ block, txIndex });
794
+ var encodeArg = (arg) => {
795
+ if (arg.type === "issuer")
796
+ return uint(ARG_TAG.issuer, BYTE_WIDTH.argTag);
797
+ return concatHex([uint(ARG_TAG.word, BYTE_WIDTH.argTag), bytesField("viewCallArgument", arg.value)]);
798
+ };
799
+ var issuerWordOf = (issuer) => issuer == null ? void 0 : padHex(issuer, { size: BYTE_WIDTH.word }).toLowerCase();
800
+ var asIssuer = (arg, issuerWord) => arg.type === "word" && issuerWord != null && arg.value.toLowerCase() === issuerWord ? { type: "issuer" } : arg;
801
+ var encodeArgs = ({ args: given, returnWord }, issuerWord) => {
802
+ const args = given.map((arg) => asIssuer(arg, issuerWord));
803
+ if (returnWord === 0 && args.length === 0)
804
+ return uint(ARGS_CODE.none, BYTE_WIDTH.argsCode);
805
+ if (returnWord === 0 && args.length === 1 && args[0].type === "issuer") {
806
+ return uint(ARGS_CODE.issuer, BYTE_WIDTH.argsCode);
807
+ }
808
+ return concatHex([
809
+ uint(ARGS_CODE.explicit, BYTE_WIDTH.argsCode),
810
+ uint(returnWord, BYTE_WIDTH.returnWord),
811
+ uint(args.length, BYTE_WIDTH.count),
812
+ ...args.map(encodeArg)
813
+ ]);
814
+ };
815
+ var encodeShareMetadata = (labels, { issuer, appKey } = {}) => {
816
+ const issuerWord = issuerWordOf(issuer);
817
+ const contracts = listOf(keyOfContract, "contract");
818
+ const selectors = listOf(keyOfSelector, "selector");
819
+ const transactions = listOf(keyOfTransaction, "transaction");
820
+ for (const label of labels) {
821
+ if (label.kind === "unlabelled")
822
+ continue;
823
+ contracts.insert(label.contract);
824
+ selectors.insert(label.selector);
825
+ if (label.kind === "event")
826
+ transactions.insert(transactionOf(label));
827
+ }
828
+ const entries = labels.map((label) => {
829
+ switch (label.kind) {
830
+ case "stored":
831
+ return concatHex([
832
+ uint(ENTRY_KIND.stored, BYTE_WIDTH.kind),
833
+ uint(contracts.positionOf(label.contract), BYTE_WIDTH.index),
834
+ uint(selectors.positionOf(label.selector), BYTE_WIDTH.index),
835
+ uint(label.block, BYTE_WIDTH.block),
836
+ encodeArgs(label, issuerWord)
837
+ ]);
838
+ case "event":
839
+ return concatHex([
840
+ uint(ENTRY_KIND.event, BYTE_WIDTH.kind),
841
+ uint(contracts.positionOf(label.contract), BYTE_WIDTH.index),
842
+ uint(transactions.positionOf(transactionOf(label)), BYTE_WIDTH.index),
843
+ uint(label.logIndex, BYTE_WIDTH.logIndex),
844
+ uint(selectors.positionOf(label.selector), BYTE_WIDTH.index)
845
+ ]);
846
+ case "unlabelled":
847
+ return uint(ENTRY_KIND.unlabelled, BYTE_WIDTH.kind);
848
+ }
849
+ });
850
+ return concatHex([
851
+ uint(LAYOUT_VERSION, BYTE_WIDTH.version),
852
+ uint(contracts.items.length, BYTE_WIDTH.count),
853
+ ...contracts.items.map((contract) => bytesField("contract", contract)),
854
+ uint(selectors.items.length, BYTE_WIDTH.count),
855
+ ...selectors.items.map((selector) => bytesField("selector", selector)),
856
+ uint(transactions.items.length, BYTE_WIDTH.count),
857
+ ...transactions.items.map(
858
+ (tx) => concatHex([uint(tx.block, BYTE_WIDTH.block), uint(tx.txIndex, BYTE_WIDTH.txIndex)])
859
+ ),
860
+ ...entries,
861
+ ...appKey == null ? [] : [uint(APP_KEY_TAG, BYTE_WIDTH.count), bytesField("appKey", appKey)]
862
+ ]);
863
+ };
864
+ var findViewFunction = (abi, name, arity) => {
865
+ const named = abi.filter((item) => item.type === "function" && item.name === name);
866
+ if (named.length === 0)
867
+ throw new Error(`share metadata: the ABI has no function ${name}`);
868
+ const fitting = named.filter((fn2) => fn2.inputs.length === arity);
869
+ if (fitting.length !== 1) {
870
+ throw new Error(
871
+ named.length === 1 ? `share metadata: ${name} takes ${named[0].inputs.length} arguments, ${arity} given` : `share metadata: no single overload of ${name} takes ${arity} arguments`
872
+ );
873
+ }
874
+ const [fn] = fitting;
875
+ if (fn.stateMutability !== "view" && fn.stateMutability !== "pure") {
876
+ throw new Error(`share metadata: ${name} is not a view function`);
877
+ }
878
+ return fn;
879
+ };
880
+ var encodeReadArg = (fn, index, value) => {
881
+ const input = fn.inputs[index];
882
+ const word = encodeAbiParameters([input], [value]);
883
+ if (size(word) !== BYTE_WIDTH.word) {
884
+ throw new Error(
885
+ `share metadata: argument ${index} of ${fn.name} is ${input.type}; only arguments of one static 32-byte word can be labelled`
886
+ );
887
+ }
888
+ return { type: "word", value: word };
889
+ };
890
+ var viewFunctionLabel = (options) => {
891
+ const { contract, block, returnWord = 0 } = options;
892
+ const values = options.args ?? [];
893
+ const fn = findViewFunction(options.abi, options.functionName, values.length);
894
+ return {
895
+ kind: "stored",
896
+ contract,
897
+ selector: toFunctionSelector(fn),
898
+ args: values.map((value, i) => encodeReadArg(fn, i, value)),
899
+ returnWord,
900
+ block
901
+ };
902
+ };
903
+ var eventLogLabel = (log) => {
904
+ const { address, blockNumber, transactionIndex, logIndex, topics } = log;
905
+ const topic0 = topics[0];
906
+ if (blockNumber == null || transactionIndex == null || logIndex == null) {
907
+ throw new Error("share metadata: a pending log has no position to label");
908
+ }
909
+ if (topic0 == null || size(topic0) !== 32)
910
+ throw new Error("share metadata: an anonymous log has no event selector");
911
+ return {
912
+ kind: "event",
913
+ contract: address,
914
+ block: blockNumber,
915
+ txIndex: transactionIndex,
916
+ logIndex,
917
+ selector: sliceHex(topic0, 0, 4)
918
+ };
919
+ };
920
+ var UNLABELLED = { kind: "unlabelled" };
921
+
872
922
  // acps/acp.ts
923
+ var sharedByName = (issuer) => `Shared by ${issuer.slice(0, 6)}\u2026${issuer.slice(-4)}`;
873
924
  var ACPUtils = {
874
925
  /**
875
926
  * Create a self acp for personal use
@@ -891,10 +942,16 @@ var ACPUtils = {
891
942
  */
892
943
  createSharing: (options) => {
893
944
  const validation = validateSharingACPOptions(options);
945
+ const { labels, appKey } = options;
946
+ if (labels != null && labels.length !== validation.handles.length) {
947
+ throw new Error(`Cannot label a share of ${validation.handles.length} handles with ${labels.length} labels`);
948
+ }
949
+ const metadata = labels != null || appKey != null ? encodeShareMetadata(labels ?? validation.handles.map(() => UNLABELLED), { issuer: validation.issuer, appKey }) : void 0;
894
950
  const sealingPair = GenerateSealingKey();
895
951
  const acp = {
896
952
  hash: ACPUtils.getHash(validation),
897
953
  ...validation,
954
+ ...metadata != null && { metadata },
898
955
  sealingPrivateKey: sealingPair.privateKey,
899
956
  sealingKey: sealingPair.publicKey,
900
957
  _signedDomain: void 0
@@ -902,9 +959,10 @@ var ACPUtils = {
902
959
  return acp;
903
960
  },
904
961
  /**
905
- * Import a shared acp from various input formats
962
+ * Import a shared acp from various input formats. The acp is named `name`, or after its issuer
963
+ * ("Shared by 0x1234…abcd"); a `name` in the share itself is ignored.
906
964
  */
907
- importShared: (options) => {
965
+ importShared: (options, { name } = {}) => {
908
966
  let parsedOptions;
909
967
  if (typeof options === "string") {
910
968
  try {
@@ -925,6 +983,7 @@ var ACPUtils = {
925
983
  const acp = {
926
984
  hash: ACPUtils.getHash(validation),
927
985
  ...validation,
986
+ name: name?.trim() || sharedByName(validation.issuer),
928
987
  sealingPrivateKey: sealingPair.privateKey,
929
988
  sealingKey: sealingPair.publicKey,
930
989
  _signedDomain: void 0
@@ -983,8 +1042,8 @@ var ACPUtils = {
983
1042
  /**
984
1043
  * Import and sign a shared acp in one operation from various input formats
985
1044
  */
986
- importSharedAndSign: async (options, publicClient, walletClient) => {
987
- const acp = ACPUtils.importShared(options);
1045
+ importSharedAndSign: async (options, publicClient, walletClient, importOptions = {}) => {
1046
+ const acp = ACPUtils.importShared(options, importOptions);
988
1047
  return ACPUtils.sign(acp, publicClient, walletClient);
989
1048
  },
990
1049
  /**
@@ -1013,7 +1072,8 @@ var ACPUtils = {
1013
1072
  issuerSignature: acp.issuerSignature,
1014
1073
  recipientSignature: acp.recipientSignature,
1015
1074
  _signedDomain: acp._signedDomain,
1016
- sealingPrivateKey: acp.sealingPrivateKey
1075
+ sealingPrivateKey: acp.sealingPrivateKey,
1076
+ ...acp.metadata != null && { metadata: acp.metadata }
1017
1077
  };
1018
1078
  },
1019
1079
  /**
@@ -1087,7 +1147,7 @@ var ACPUtils = {
1087
1147
  /**
1088
1148
  * Export acp data for sharing (strips the private component).
1089
1149
  * Fixed `SharedACP` shape — every field always present, aligned with
1090
- * `ACPPublic` and the on-chain sharing payload.
1150
+ * `ACPPublic` and the on-chain sharing payload — plus `metadata` when the acp has labels.
1091
1151
  */
1092
1152
  export: (acp) => {
1093
1153
  if (acp.type !== "sharing") {
@@ -1101,7 +1161,6 @@ var ACPUtils = {
1101
1161
  );
1102
1162
  }
1103
1163
  const shared = {
1104
- name: acp.name,
1105
1164
  type: acp.type,
1106
1165
  issuer: acp.issuer,
1107
1166
  expiration: acp.expiration,
@@ -1111,7 +1170,8 @@ var ACPUtils = {
1111
1170
  scope: acp.scope,
1112
1171
  contracts: acp.contracts,
1113
1172
  handles: acp.handles,
1114
- issuerSignature: acp.issuerSignature
1173
+ issuerSignature: acp.issuerSignature,
1174
+ ...acp.metadata != null && acp.metadata !== "0x" && { metadata: acp.metadata }
1115
1175
  };
1116
1176
  return JSON.stringify(shared, void 0, 2);
1117
1177
  },
@@ -1197,11 +1257,14 @@ var ACP_REVOKER_ABI = parseAbi([
1197
1257
  ]);
1198
1258
  var ACP_SHARE_REGISTRY_ABI = parseAbi([
1199
1259
  "struct ACP { address issuer; uint64 expiration; address recipient; uint256 revokerData; address revokerContract; uint8 scope; address[] contracts; bytes32[] handles; bytes32 sealingKey; bytes issuerSignature; bytes recipientSignature; }",
1200
- "function share(ACP calldata acp) external returns (bytes32)",
1260
+ "struct ShareHeader { address issuer; uint64 expiration; address recipient; uint64 blockNumber; address revokerContract; uint256 revokerData; }",
1261
+ "function share(ACP calldata acp, bytes calldata metadata) external returns (bytes32)",
1201
1262
  "function removeShare(bytes32 shareId) external",
1202
- "function sharesFor(address recipient) external view returns (ACP[] memory)",
1203
- "function getShare(bytes32 shareId) external view returns (ACP memory)",
1204
- "function isShareValid(bytes32 shareId) external view returns (bool)"
1263
+ "function sharesFor(address recipient) external view returns (bytes32[] shareIds, ShareHeader[] headers)",
1264
+ "function getShare(bytes32 shareId) external view returns (ShareHeader memory)",
1265
+ "function isShareValid(bytes32 shareId) external view returns (bool)",
1266
+ "event Shared(address indexed recipient, address indexed issuer, bytes32 indexed shareId, ACP acp, bytes metadata)",
1267
+ "event ShareRemoved(address indexed recipient, address indexed issuer, bytes32 indexed shareId)"
1205
1268
  ]);
1206
1269
  var ACP_SHARE_TUPLE_ABI = [
1207
1270
  {
@@ -1237,11 +1300,393 @@ var computeShareId = (acp) => {
1237
1300
  return keccak256(encodeAbiParameters(ACP_SHARE_TUPLE_ABI, [p]));
1238
1301
  };
1239
1302
  var shareIdOfChainShare = (share) => keccak256(encodeAbiParameters(ACP_SHARE_TUPLE_ABI, [share]));
1303
+ var messageOf = (error) => error instanceof Error ? error.message : String(error);
1304
+ var readPostedShares = async (publicClient, registry, headers) => {
1305
+ const idsByBlock = /* @__PURE__ */ new Map();
1306
+ for (const { shareId, header } of headers) {
1307
+ idsByBlock.set(header.blockNumber, [...idsByBlock.get(header.blockNumber) ?? [], shareId]);
1308
+ }
1309
+ const found = /* @__PURE__ */ new Map();
1310
+ await Promise.all(
1311
+ [...idsByBlock].map(async ([block, shareIds]) => {
1312
+ let logs;
1313
+ try {
1314
+ logs = await publicClient.getContractEvents({
1315
+ address: registry,
1316
+ abi: ACP_SHARE_REGISTRY_ABI,
1317
+ eventName: "Shared",
1318
+ args: { shareId: shareIds },
1319
+ fromBlock: block,
1320
+ toBlock: block,
1321
+ strict: true
1322
+ });
1323
+ } catch (error) {
1324
+ for (const shareId of shareIds) {
1325
+ found.set(shareId.toLowerCase(), {
1326
+ reason: `the Shared events of block ${block} could not be read: ${messageOf(error)}`
1327
+ });
1328
+ }
1329
+ return;
1330
+ }
1331
+ for (const { args } of logs) {
1332
+ const hashes = shareIdOfChainShare(args.acp).toLowerCase() === args.shareId.toLowerCase();
1333
+ found.set(
1334
+ args.shareId.toLowerCase(),
1335
+ hashes ? { share: args.acp, metadata: args.metadata } : { reason: "the payload in its Shared event does not hash to its id" }
1336
+ );
1337
+ }
1338
+ })
1339
+ );
1340
+ const result = { posted: [], unreadable: [] };
1341
+ for (const { shareId, header } of headers) {
1342
+ const entry = found.get(shareId.toLowerCase());
1343
+ if (entry == null) {
1344
+ result.unreadable.push({
1345
+ shareId,
1346
+ header,
1347
+ reason: `no Shared event in block ${header.blockNumber}, where the registry points`
1348
+ });
1349
+ } else if ("reason" in entry) {
1350
+ result.unreadable.push({ shareId, header, reason: entry.reason });
1351
+ } else {
1352
+ result.posted.push({ shareId, header, ...entry });
1353
+ }
1354
+ }
1355
+ return result;
1356
+ };
1357
+ var readSharesFor = async (publicClient, registry, recipient) => {
1358
+ const [shareIds, headers] = await publicClient.readContract({
1359
+ address: registry,
1360
+ abi: ACP_SHARE_REGISTRY_ABI,
1361
+ functionName: "sharesFor",
1362
+ args: [recipient]
1363
+ });
1364
+ return readPostedShares(
1365
+ publicClient,
1366
+ registry,
1367
+ shareIds.map((shareId, i) => ({ shareId, header: headers[i] }))
1368
+ );
1369
+ };
1370
+ var readShare = async (publicClient, registry, shareId) => {
1371
+ const header = await publicClient.readContract({
1372
+ address: registry,
1373
+ abi: ACP_SHARE_REGISTRY_ABI,
1374
+ functionName: "getShare",
1375
+ args: [shareId]
1376
+ });
1377
+ if (header.issuer === "0x0000000000000000000000000000000000000000")
1378
+ return null;
1379
+ const { posted, unreadable } = await readPostedShares(publicClient, registry, [{ shareId, header }]);
1380
+ if (unreadable.length > 0)
1381
+ throw new Error(`Share ${shareId}: ${unreadable[0].reason}`);
1382
+ return posted[0];
1383
+ };
1384
+ var readerOf = (blob) => {
1385
+ let offset = 0;
1386
+ const take = (width) => {
1387
+ if (offset + width > size(blob))
1388
+ throw new Error("share metadata: the blob ends in the middle of a field");
1389
+ offset += width;
1390
+ return sliceHex(blob, offset - width, offset);
1391
+ };
1392
+ return {
1393
+ take,
1394
+ takeNumber: (width) => hexToNumber(take(width)),
1395
+ done: () => offset === size(blob),
1396
+ remaining: () => size(blob) - offset
1397
+ };
1398
+ };
1399
+ var takeList = (reader, takeItem) => Array.from({ length: reader.takeNumber(BYTE_WIDTH.count) }, takeItem);
1400
+ var takeFrom = (reader, list, what) => {
1401
+ const position = reader.takeNumber(BYTE_WIDTH.index);
1402
+ if (position >= list.length) {
1403
+ throw new Error(`share metadata: ${what} ${position} is outside the ${what} list`);
1404
+ }
1405
+ return list[position];
1406
+ };
1407
+ var decodeArg = (reader) => {
1408
+ const tag = reader.takeNumber(BYTE_WIDTH.argTag);
1409
+ if (tag === ARG_TAG.issuer)
1410
+ return { type: "issuer" };
1411
+ if (tag === ARG_TAG.word)
1412
+ return { type: "word", value: reader.take(BYTE_WIDTH.word) };
1413
+ throw new Error(`share metadata: unknown argument tag ${tag}`);
1414
+ };
1415
+ var decodeArgs = (reader) => {
1416
+ const code = reader.takeNumber(BYTE_WIDTH.argsCode);
1417
+ if (code === ARGS_CODE.none)
1418
+ return { args: [], returnWord: 0 };
1419
+ if (code === ARGS_CODE.issuer)
1420
+ return { args: [{ type: "issuer" }], returnWord: 0 };
1421
+ if (code !== ARGS_CODE.explicit)
1422
+ throw new Error(`share metadata: unknown args code ${code}`);
1423
+ const returnWord = reader.takeNumber(BYTE_WIDTH.returnWord);
1424
+ return { args: takeList(reader, () => decodeArg(reader)), returnWord };
1425
+ };
1426
+ var takeAppKey = (reader) => {
1427
+ if (reader.done())
1428
+ return void 0;
1429
+ const isKey = reader.remaining() === BYTE_WIDTH.count + BYTE_WIDTH.word && reader.takeNumber(BYTE_WIDTH.count) === APP_KEY_TAG;
1430
+ if (!isKey)
1431
+ throw new Error("share metadata: the blob has more entries than the share has ctHashes");
1432
+ return reader.take(BYTE_WIDTH.word);
1433
+ };
1434
+ var decodeShareMetadataFull = (blob, handles) => {
1435
+ const reader = readerOf(blob);
1436
+ const version = reader.takeNumber(BYTE_WIDTH.version);
1437
+ if (version !== LAYOUT_VERSION)
1438
+ throw new Error(`share metadata: unsupported version ${version}`);
1439
+ const contracts = takeList(reader, () => getAddress(reader.take(BYTE_WIDTH.address)));
1440
+ const selectors = takeList(reader, () => reader.take(BYTE_WIDTH.selector));
1441
+ const transactions = takeList(reader, () => ({
1442
+ block: hexToBigInt(reader.take(BYTE_WIDTH.block)),
1443
+ txIndex: reader.takeNumber(BYTE_WIDTH.txIndex)
1444
+ }));
1445
+ const labels = handles.map(() => {
1446
+ const kind = reader.takeNumber(BYTE_WIDTH.kind);
1447
+ switch (kind) {
1448
+ case ENTRY_KIND.stored: {
1449
+ const contract = takeFrom(reader, contracts, "contract");
1450
+ const selector = takeFrom(reader, selectors, "selector");
1451
+ const block = hexToBigInt(reader.take(BYTE_WIDTH.block));
1452
+ return { kind: "stored", contract, selector, ...decodeArgs(reader), block };
1453
+ }
1454
+ case ENTRY_KIND.event: {
1455
+ const contract = takeFrom(reader, contracts, "contract");
1456
+ const { block, txIndex } = takeFrom(reader, transactions, "transaction");
1457
+ const logIndex = reader.takeNumber(BYTE_WIDTH.logIndex);
1458
+ const selector = takeFrom(reader, selectors, "selector");
1459
+ return { kind: "event", contract, block, txIndex, logIndex, selector };
1460
+ }
1461
+ case ENTRY_KIND.unlabelled:
1462
+ return { kind: "unlabelled" };
1463
+ default:
1464
+ throw new Error(`share metadata: unknown entry kind ${kind}`);
1465
+ }
1466
+ });
1467
+ const appKey = takeAppKey(reader);
1468
+ if (!reader.done())
1469
+ throw new Error("share metadata: the blob has more entries than the share has ctHashes");
1470
+ return { labels, appKey };
1471
+ };
1472
+ var decodeShareMetadata = (blob, handles) => decodeShareMetadataFull(blob, handles).labels;
1473
+ var decodeShareAppKey = (metadata, handles) => metadata == null || metadata === "0x" ? void 0 : decodeShareMetadataFull(metadata, handles).appKey;
1474
+ var sameWord = (a, b) => a.toLowerCase() === b.toLowerCase();
1475
+ var wordsOf = (data) => {
1476
+ const count = Math.floor(size(data) / BYTE_WIDTH.word);
1477
+ return Array.from(
1478
+ { length: count },
1479
+ (_, index) => sliceHex(data, index * BYTE_WIDTH.word, (index + 1) * BYTE_WIDTH.word)
1480
+ );
1481
+ };
1482
+ var storedCallData = (label, issuer) => concatHex([
1483
+ label.selector,
1484
+ ...label.args.map((arg) => arg.type === "issuer" ? padHex(issuer, { size: BYTE_WIDTH.word }) : arg.value)
1485
+ ]);
1486
+ var checkStored = (label, handle, data) => {
1487
+ const found = data ? wordsOf(data)[label.returnWord] : void 0;
1488
+ return found && sameWord(found, handle) ? "verified" : "mismatch";
1489
+ };
1490
+ var checkEvent = (label, handle, logs) => {
1491
+ const log = logs.find((l) => l.logIndex === label.logIndex);
1492
+ if (log == null)
1493
+ return "mismatch";
1494
+ if (log.transactionIndex !== label.txIndex)
1495
+ return "mismatch";
1496
+ const topic0 = log.topics[0];
1497
+ if (topic0 == null || !topic0.toLowerCase().startsWith(label.selector.toLowerCase()))
1498
+ return "mismatch";
1499
+ const carried = [...log.topics.slice(1), ...wordsOf(log.data)].some((word) => word != null && sameWord(word, handle));
1500
+ return carried ? "verified" : "mismatch";
1501
+ };
1502
+ var callAt = async (publicClient, to, data, blockNumber) => (await publicClient.call({ to, data, blockNumber })).data;
1503
+ var logsAt = (publicClient, address, block) => publicClient.getLogs({ address, fromBlock: block, toBlock: block });
1504
+ var verifyShareLabel = async (label, handle, publicClient, issuer) => {
1505
+ try {
1506
+ switch (label.kind) {
1507
+ case "stored":
1508
+ return checkStored(
1509
+ label,
1510
+ handle,
1511
+ await callAt(publicClient, label.contract, storedCallData(label, issuer), label.block)
1512
+ );
1513
+ case "event":
1514
+ return checkEvent(label, handle, await logsAt(publicClient, label.contract, label.block));
1515
+ case "unlabelled":
1516
+ return "unverifiable";
1517
+ }
1518
+ } catch {
1519
+ return "unverifiable";
1520
+ }
1521
+ };
1522
+ var verifyShareLabels = async ({
1523
+ labels,
1524
+ handles,
1525
+ issuer,
1526
+ publicClient,
1527
+ verify = "all"
1528
+ }) => {
1529
+ if (labels.length !== handles.length) {
1530
+ throw new Error(`share metadata: ${labels.length} labels for ${handles.length} ctHashes`);
1531
+ }
1532
+ const requests = /* @__PURE__ */ new Map();
1533
+ const once = (key, request) => {
1534
+ if (!requests.has(key))
1535
+ requests.set(key, request());
1536
+ return requests.get(key);
1537
+ };
1538
+ return Promise.all(
1539
+ labels.map(async (label, i) => {
1540
+ const handle = handles[i];
1541
+ try {
1542
+ switch (label.kind) {
1543
+ case "stored": {
1544
+ if (verify !== "all")
1545
+ return "skipped";
1546
+ const data = storedCallData(label, issuer);
1547
+ const key = `call:${label.contract.toLowerCase()}:${label.block}:${data}`;
1548
+ return checkStored(
1549
+ label,
1550
+ handle,
1551
+ await once(key, () => callAt(publicClient, label.contract, data, label.block))
1552
+ );
1553
+ }
1554
+ case "event": {
1555
+ if (verify === "none")
1556
+ return "skipped";
1557
+ const key = `logs:${label.contract.toLowerCase()}:${label.block}`;
1558
+ return checkEvent(label, handle, await once(key, () => logsAt(publicClient, label.contract, label.block)));
1559
+ }
1560
+ case "unlabelled":
1561
+ return verify === "none" ? "skipped" : "unverifiable";
1562
+ }
1563
+ } catch {
1564
+ return "unverifiable";
1565
+ }
1566
+ })
1567
+ );
1568
+ };
1569
+ var abiOf = (abis, contract) => {
1570
+ const wanted = contract.toLowerCase();
1571
+ const key = Object.keys(abis).find((address) => address.toLowerCase() === wanted);
1572
+ return key ? abis[key] : void 0;
1573
+ };
1574
+ var paramOf = ({ name, type, ...rest }) => {
1575
+ const param = { type };
1576
+ if (name)
1577
+ param.name = name;
1578
+ if ("indexed" in rest && typeof rest.indexed === "boolean")
1579
+ param.indexed = rest.indexed;
1580
+ return param;
1581
+ };
1582
+ var findFunction = (abi, selector) => abi?.find(
1583
+ (item) => item.type === "function" && toFunctionSelector(item).toLowerCase() === selector.toLowerCase()
1584
+ );
1585
+ var findEvent = (abi, selector) => abi?.find(
1586
+ (item) => item.type === "event" && toEventSelector(item).toLowerCase().startsWith(selector.toLowerCase())
1587
+ );
1588
+ var decodeWord = (input, raw) => {
1589
+ if (input == null)
1590
+ return raw;
1591
+ try {
1592
+ return decodeAbiParameters([input], raw)[0];
1593
+ } catch {
1594
+ return raw;
1595
+ }
1596
+ };
1597
+ var describeStored = (base, label, abis, issuer) => {
1598
+ const fn = findFunction(abiOf(abis, label.contract), label.selector);
1599
+ const args = label.args.map((arg, i) => {
1600
+ const input = fn?.inputs[i];
1601
+ const param = input ? paramOf(input) : { type: "bytes32" };
1602
+ if (arg.type === "issuer") {
1603
+ return {
1604
+ ...param,
1605
+ isIssuer: true,
1606
+ raw: issuer ? padHex(issuer, { size: 32 }) : void 0,
1607
+ value: issuer
1608
+ };
1609
+ }
1610
+ return { ...param, isIssuer: false, raw: arg.value, value: decodeWord(input, arg.value) };
1611
+ });
1612
+ const output = fn?.outputs[label.returnWord];
1613
+ return {
1614
+ ...base,
1615
+ kind: "stored",
1616
+ label,
1617
+ contract: label.contract,
1618
+ block: label.block,
1619
+ selector: label.selector,
1620
+ function: fn ? { name: fn.name, signature: toFunctionSignature(fn), inputs: fn.inputs.map(paramOf) } : null,
1621
+ args,
1622
+ output: output ? paramOf(output) : null
1623
+ };
1624
+ };
1625
+ var describeEvent = (base, label, abis) => {
1626
+ const event = findEvent(abiOf(abis, label.contract), label.selector);
1627
+ return {
1628
+ ...base,
1629
+ kind: "event",
1630
+ label,
1631
+ contract: label.contract,
1632
+ block: label.block,
1633
+ txIndex: label.txIndex,
1634
+ logIndex: label.logIndex,
1635
+ selector: label.selector,
1636
+ event: event ? { name: event.name, signature: toEventSignature(event), inputs: event.inputs.map(paramOf) } : null
1637
+ };
1638
+ };
1639
+ var describeShareLabels = (labels, handles, abis = {}, options = {}) => labels.map((label, index) => {
1640
+ const base = { index, handle: handles[index] };
1641
+ switch (label.kind) {
1642
+ case "stored":
1643
+ return describeStored(base, label, abis, options.issuer);
1644
+ case "event":
1645
+ return describeEvent(base, label, abis);
1646
+ case "unlabelled":
1647
+ return { ...base, kind: "unlabelled", label };
1648
+ }
1649
+ });
1650
+ var describeShareMetadata = (share, abis = {}) => {
1651
+ const { issuer, handles, metadata } = share;
1652
+ if (metadata == null || metadata === "0x")
1653
+ return null;
1654
+ return describeShareLabels(decodeShareMetadata(metadata, handles), handles, abis, { issuer });
1655
+ };
1656
+
1657
+ // acps/share-metadata/erc7984.ts
1658
+ var ERC7984_ABI = [
1659
+ {
1660
+ type: "function",
1661
+ name: "confidentialBalanceOf",
1662
+ stateMutability: "view",
1663
+ inputs: [{ name: "account", type: "address", internalType: "address" }],
1664
+ outputs: [{ name: "", type: "bytes32", internalType: "euint64" }]
1665
+ },
1666
+ {
1667
+ type: "event",
1668
+ name: "ConfidentialTransfer",
1669
+ anonymous: false,
1670
+ inputs: [
1671
+ { name: "from", type: "address", indexed: true, internalType: "address" },
1672
+ { name: "to", type: "address", indexed: true, internalType: "address" },
1673
+ { name: "amount", type: "bytes32", indexed: true, internalType: "euint64" }
1674
+ ]
1675
+ }
1676
+ ];
1677
+ var shareAppKey = (app) => keccak256(stringToHex(app));
1240
1678
  var ACP_STORE_DEFAULTS = {
1241
1679
  acps: {},
1242
1680
  activeACPHash: {}
1243
1681
  };
1244
1682
  var ACP_STORE_VERSION = 3;
1683
+ var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
1684
+ var resolveAccountKey = (records, account) => {
1685
+ if (records == null || account in records)
1686
+ return account;
1687
+ const lower = account.toLowerCase();
1688
+ return Object.keys(records).find((key) => key.toLowerCase() === lower) ?? account;
1689
+ };
1245
1690
  var _acpStore = createStore()(
1246
1691
  persist(() => ACP_STORE_DEFAULTS, {
1247
1692
  name: "cofhesdk-acps",
@@ -1250,12 +1695,23 @@ var _acpStore = createStore()(
1250
1695
  if (version < ACP_STORE_VERSION)
1251
1696
  return ACP_STORE_DEFAULTS;
1252
1697
  return persistedState;
1698
+ },
1699
+ // Runs on every rehydrate, including a corrupt state saved at the current version that
1700
+ // `migrate` passes through unchanged. Consumers that read the raw snapshot (e.g. the React
1701
+ // hooks) never go through `clearStaleStore`, so the shape has to be fixed here.
1702
+ merge: (persistedState, currentState) => {
1703
+ const persisted = isRecord(persistedState) ? persistedState : {};
1704
+ return {
1705
+ ...currentState,
1706
+ acps: isRecord(persisted.acps) ? persisted.acps : currentState.acps,
1707
+ activeACPHash: isRecord(persisted.activeACPHash) ? persisted.activeACPHash : currentState.activeACPHash
1708
+ };
1253
1709
  }
1254
1710
  })
1255
1711
  );
1256
1712
  var clearStaleStore = () => {
1257
1713
  const state = _acpStore.getState();
1258
- const hasExpectedStructure = state && typeof state === "object" && "acps" in state && "activeACPHash" in state && typeof state.acps === "object" && typeof state.activeACPHash === "object";
1714
+ const hasExpectedStructure = isRecord(state) && isRecord(state.acps) && isRecord(state.activeACPHash);
1259
1715
  if (hasExpectedStructure)
1260
1716
  return;
1261
1717
  _acpStore.setState({ acps: {}, activeACPHash: {} });
@@ -1264,7 +1720,8 @@ var getACP = (chainId, account, hash) => {
1264
1720
  clearStaleStore();
1265
1721
  if (chainId == null || account == null || hash == null)
1266
1722
  return;
1267
- const savedACP = _acpStore.getState().acps[chainId]?.[account]?.[hash];
1723
+ const accountACPs = _acpStore.getState().acps[chainId];
1724
+ const savedACP = accountACPs?.[resolveAccountKey(accountACPs, account)]?.[hash];
1268
1725
  if (savedACP == null)
1269
1726
  return;
1270
1727
  return ACPUtils.deserialize(savedACP);
@@ -1273,14 +1730,16 @@ var getActiveACP = (chainId, account) => {
1273
1730
  clearStaleStore();
1274
1731
  if (chainId == null || account == null)
1275
1732
  return;
1276
- const activeACPHash = _acpStore.getState().activeACPHash[chainId]?.[account];
1733
+ const activeHashes = _acpStore.getState().activeACPHash[chainId];
1734
+ const activeACPHash = activeHashes?.[resolveAccountKey(activeHashes, account)];
1277
1735
  return getACP(chainId, account, activeACPHash);
1278
1736
  };
1279
1737
  var getACPs = (chainId, account) => {
1280
1738
  clearStaleStore();
1281
1739
  if (chainId == null || account == null)
1282
1740
  return {};
1283
- return Object.entries(_acpStore.getState().acps[chainId]?.[account] ?? {}).reduce(
1741
+ const accountACPs = _acpStore.getState().acps[chainId];
1742
+ return Object.entries(accountACPs?.[resolveAccountKey(accountACPs, account)] ?? {}).reduce(
1284
1743
  (acc, [hash, acp]) => {
1285
1744
  if (acp == void 0)
1286
1745
  return acc;
@@ -1295,9 +1754,10 @@ var setACP = (chainId, account, acp) => {
1295
1754
  produce((state) => {
1296
1755
  if (state.acps[chainId] == null)
1297
1756
  state.acps[chainId] = {};
1298
- if (state.acps[chainId][account] == null)
1299
- state.acps[chainId][account] = {};
1300
- state.acps[chainId][account][acp.hash] = ACPUtils.serialize(acp);
1757
+ const key = resolveAccountKey(state.acps[chainId], account);
1758
+ if (state.acps[chainId][key] == null)
1759
+ state.acps[chainId][key] = {};
1760
+ state.acps[chainId][key][acp.hash] = ACPUtils.serialize(acp);
1301
1761
  })
1302
1762
  );
1303
1763
  };
@@ -1309,13 +1769,14 @@ var removeACP = (chainId, account, hash) => {
1309
1769
  state.acps[chainId] = {};
1310
1770
  if (state.activeACPHash[chainId] == null)
1311
1771
  state.activeACPHash[chainId] = {};
1312
- const accountACPs = state.acps[chainId][account];
1772
+ const accountACPs = state.acps[chainId][resolveAccountKey(state.acps[chainId], account)];
1313
1773
  if (accountACPs == null)
1314
1774
  return;
1315
1775
  if (accountACPs[hash] == null)
1316
1776
  return;
1317
- if (state.activeACPHash[chainId][account] === hash) {
1318
- state.activeACPHash[chainId][account] = void 0;
1777
+ const activeKey = resolveAccountKey(state.activeACPHash[chainId], account);
1778
+ if (state.activeACPHash[chainId][activeKey] === hash) {
1779
+ state.activeACPHash[chainId][activeKey] = void 0;
1319
1780
  }
1320
1781
  accountACPs[hash] = void 0;
1321
1782
  })
@@ -1325,7 +1786,8 @@ var getActiveACPHash = (chainId, account) => {
1325
1786
  clearStaleStore();
1326
1787
  if (chainId == null || account == null)
1327
1788
  return void 0;
1328
- return _acpStore.getState().activeACPHash[chainId]?.[account];
1789
+ const activeHashes = _acpStore.getState().activeACPHash[chainId];
1790
+ return activeHashes?.[resolveAccountKey(activeHashes, account)];
1329
1791
  };
1330
1792
  var setActiveACPHash = (chainId, account, hash) => {
1331
1793
  clearStaleStore();
@@ -1333,7 +1795,7 @@ var setActiveACPHash = (chainId, account, hash) => {
1333
1795
  produce((state) => {
1334
1796
  if (state.activeACPHash[chainId] == null)
1335
1797
  state.activeACPHash[chainId] = {};
1336
- state.activeACPHash[chainId][account] = hash;
1798
+ state.activeACPHash[chainId][resolveAccountKey(state.activeACPHash[chainId], account)] = hash;
1337
1799
  })
1338
1800
  );
1339
1801
  };
@@ -1342,7 +1804,7 @@ var removeActiveACPHash = (chainId, account) => {
1342
1804
  _acpStore.setState(
1343
1805
  produce((state) => {
1344
1806
  if (state.activeACPHash[chainId])
1345
- state.activeACPHash[chainId][account] = void 0;
1807
+ state.activeACPHash[chainId][resolveAccountKey(state.activeACPHash[chainId], account)] = void 0;
1346
1808
  })
1347
1809
  );
1348
1810
  };
@@ -1363,4 +1825,4 @@ var acpStore = {
1363
1825
  resetStore
1364
1826
  };
1365
1827
 
1366
- export { ACPScope, ACPUtils, ACP_REVOKER_ABI, ACP_SHARE_REGISTRY_ABI, ACP_SHARE_TUPLE_ABI, ACP_STORE_DEFAULTS, CofheError, CofheErrorCode, GenerateSealingKey, ImportACPOptionsValidator, ImportACPValidator, SelfACPOptionsValidator, SelfACPValidator, SharingACPOptionsValidator, SharingACPValidator, SignatureTypes, SignatureUtils, ValidationUtils, _acpStore, acpStore, addressNotZeroSchema, addressSchema, bytesNotEmptySchema, bytesSchema, clearAclServedAddresses, clearStaleStore, computeShareId, contractsSchema, getACP, getACPs, getAclAddress, getAclServedAddresses, getActiveACP, getActiveACPHash, getSignatureTypesAndMessage, getTaskManagerAddress, handlesSchema, isCofheError, removeACP, removeActiveACPHash, resetStore, seal, setACP, setActiveACPHash, shareIdOfChainShare, toChainShare, unsealWithPrivateKey, validateImportACP, validateImportACPOptions, validateSelfACP, validateSelfACPOptions, validateSharingACP, validateSharingACPOptions };
1828
+ export { ACPScope, ACPUtils, ACP_REVOKER_ABI, ACP_SHARE_REGISTRY_ABI, ACP_SHARE_TUPLE_ABI, ACP_STORE_DEFAULTS, ERC7984_ABI, GenerateSealingKey, ImportACPOptionsValidator, ImportACPValidator, LAYOUT_VERSION, SelfACPOptionsValidator, SelfACPValidator, SharingACPOptionsValidator, SharingACPValidator, SignatureTypes, SignatureUtils, UNLABELLED, ValidationUtils, _acpStore, acpStore, addressNotZeroSchema, addressSchema, bytesNotEmptySchema, bytesSchema, clearAclServedAddresses, clearStaleStore, computeShareId, contractsSchema, decodeShareAppKey, decodeShareMetadata, decodeShareMetadataFull, describeShareLabels, describeShareMetadata, encodeShareMetadata, eventLogLabel, getACP, getACPs, getAclAddress, getAclServedAddresses, getActiveACP, getActiveACPHash, getSignatureTypesAndMessage, getTaskManagerAddress, handlesSchema, readPostedShares, readShare, readSharesFor, removeACP, removeActiveACPHash, resetStore, seal, setACP, setActiveACPHash, shareAppKey, shareIdOfChainShare, toChainShare, unsealWithPrivateKey, validateImportACP, validateImportACPOptions, validateSelfACP, validateSelfACPOptions, validateSharingACP, validateSharingACPOptions, verifyShareLabel, verifyShareLabels, viewFunctionLabel };