@oma3/omatrust 0.1.0-alpha.0 → 0.1.0-alpha.10

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 (36) hide show
  1. package/README.md +72 -7
  2. package/dist/identity/index.cjs +2 -3
  3. package/dist/identity/index.cjs.map +1 -1
  4. package/dist/identity/index.js +3 -4
  5. package/dist/identity/index.js.map +1 -1
  6. package/dist/index-B9KW02US.d.cts +119 -0
  7. package/dist/index-DXrwBex9.d.ts +119 -0
  8. package/dist/index.cjs +657 -93
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +2 -1
  11. package/dist/index.d.ts +2 -1
  12. package/dist/index.js +658 -94
  13. package/dist/index.js.map +1 -1
  14. package/dist/reputation/index.browser.cjs +2133 -0
  15. package/dist/reputation/index.browser.cjs.map +1 -0
  16. package/dist/reputation/index.browser.d.cts +14 -0
  17. package/dist/reputation/index.browser.d.ts +14 -0
  18. package/dist/reputation/index.browser.js +2071 -0
  19. package/dist/reputation/index.browser.js.map +1 -0
  20. package/dist/reputation/index.cjs +676 -92
  21. package/dist/reputation/index.cjs.map +1 -1
  22. package/dist/reputation/index.d.cts +2 -1
  23. package/dist/reputation/index.d.ts +2 -1
  24. package/dist/reputation/index.js +670 -94
  25. package/dist/reputation/index.js.map +1 -1
  26. package/dist/subject-ownership-CXvzEjpH.d.cts +434 -0
  27. package/dist/subject-ownership-CXvzEjpH.d.ts +434 -0
  28. package/dist/widgets/index.cjs +195 -0
  29. package/dist/widgets/index.cjs.map +1 -0
  30. package/dist/widgets/index.d.cts +134 -0
  31. package/dist/widgets/index.d.ts +134 -0
  32. package/dist/widgets/index.js +185 -0
  33. package/dist/widgets/index.js.map +1 -0
  34. package/package.json +33 -6
  35. package/dist/index-ChbJxwOA.d.cts +0 -415
  36. package/dist/index-ChbJxwOA.d.ts +0 -415
package/dist/index.cjs CHANGED
@@ -158,7 +158,7 @@ function extractDidIdentifier(did) {
158
158
  }
159
159
  function normalizeDomain(domain) {
160
160
  assertString(domain, "domain", "INVALID_DID");
161
- return domain.trim().toLowerCase().replace(/\.$/, "");
161
+ return domain.trim().toLowerCase().replace(/\.$/, "").replace(/^www\./, "");
162
162
  }
163
163
  function normalizeDidWeb(input) {
164
164
  assertString(input, "input", "INVALID_DID");
@@ -247,8 +247,7 @@ function computeDidAddress(didHash) {
247
247
  if (!/^0x[0-9a-fA-F]{64}$/.test(didHash)) {
248
248
  throw new OmaTrustError("INVALID_DID", "didHash must be 32-byte hex", { didHash });
249
249
  }
250
- const truncated = `0x${didHash.slice(-40)}`;
251
- return ethers.getAddress(truncated);
250
+ return `0x${didHash.slice(-40).toLowerCase()}`;
252
251
  }
253
252
  function didToAddress(did) {
254
253
  return computeDidAddress(computeDidHash(did));
@@ -362,6 +361,7 @@ function hashCanonicalizedJson(obj, algorithm) {
362
361
  var reputation_exports = {};
363
362
  __export(reputation_exports, {
364
363
  buildDelegatedAttestationTypedData: () => buildDelegatedAttestationTypedData,
364
+ buildDelegatedTypedDataFromEncoded: () => buildDelegatedTypedDataFromEncoded,
365
365
  buildDnsTxtRecord: () => buildDnsTxtRecord,
366
366
  buildEip712Domain: () => buildEip712Domain,
367
367
  calculateAverageUserReviewRating: () => calculateAverageUserReviewRating,
@@ -385,6 +385,7 @@ __export(reputation_exports, {
385
385
  formatSchemaUid: () => formatSchemaUid,
386
386
  formatTransferAmount: () => formatTransferAmount,
387
387
  getAttestation: () => getAttestation,
388
+ getAttestationsByAttester: () => getAttestationsByAttester,
388
389
  getAttestationsForDid: () => getAttestationsForDid,
389
390
  getChainConstants: () => getChainConstants,
390
391
  getExplorerAddressUrl: () => getExplorerAddressUrl,
@@ -400,16 +401,22 @@ __export(reputation_exports, {
400
401
  normalizeSchema: () => normalizeSchema,
401
402
  parseDnsTxtRecord: () => parseDnsTxtRecord,
402
403
  prepareDelegatedAttestation: () => prepareDelegatedAttestation,
404
+ revokeAttestation: () => revokeAttestation,
403
405
  schemaToString: () => schemaToString,
404
406
  splitSignature: () => splitSignature,
405
407
  submitAttestation: () => submitAttestation,
406
408
  submitDelegatedAttestation: () => submitDelegatedAttestation,
409
+ validateAttestationData: () => validateAttestationData,
407
410
  verifyAttestation: () => verifyAttestation,
408
411
  verifyDidDocumentControllerDid: () => verifyDidDocumentControllerDid,
412
+ verifyDidJsonControllerDid: () => verifyDidJsonControllerDid,
413
+ verifyDidPkhOwnership: () => verifyDidPkhOwnership,
414
+ verifyDidWebOwnership: () => verifyDidWebOwnership,
409
415
  verifyDnsTxtControllerDid: () => verifyDnsTxtControllerDid,
410
416
  verifyEip712Signature: () => verifyEip712Signature,
411
417
  verifyProof: () => verifyProof,
412
- verifySchemaExists: () => verifySchemaExists
418
+ verifySchemaExists: () => verifySchemaExists,
419
+ verifySubjectOwnership: () => verifySubjectOwnership
413
420
  });
414
421
  function normalizeSchema(schema) {
415
422
  if (Array.isArray(schema)) {
@@ -445,6 +452,13 @@ function encodeAttestationData(schema, data) {
445
452
  if (!data || typeof data !== "object") {
446
453
  throw new OmaTrustError("INVALID_INPUT", "data must be an object");
447
454
  }
455
+ const validationErrors = validateAttestationData(schema, data);
456
+ if (validationErrors.length > 0) {
457
+ const summary = validationErrors.map((error) => `Field "${error.schemaFieldName}" (${error.expectedType}) got ${error.providedType}`).join("; ");
458
+ throw new OmaTrustError("INVALID_INPUT", `Attestation data validation failed: ${summary}`, {
459
+ errors: validationErrors
460
+ });
461
+ }
448
462
  const fields = normalizeSchema(schema);
449
463
  const schemaString = schemaToString(fields);
450
464
  const encoder = new easSdk.SchemaEncoder(schemaString);
@@ -457,6 +471,99 @@ function encodeAttestationData(schema, data) {
457
471
  );
458
472
  return encoded;
459
473
  }
474
+ function getActualType(value) {
475
+ if (value === null) {
476
+ return "null";
477
+ }
478
+ if (value === void 0) {
479
+ return "undefined";
480
+ }
481
+ if (Array.isArray(value)) {
482
+ return "array";
483
+ }
484
+ if (typeof value === "number") {
485
+ return Number.isFinite(value) ? "number" : "non-finite-number";
486
+ }
487
+ return typeof value;
488
+ }
489
+ function isNumericValue(value, allowNegative) {
490
+ if (typeof value === "bigint") {
491
+ return allowNegative || value >= 0n;
492
+ }
493
+ if (typeof value === "number") {
494
+ if (!Number.isFinite(value) || !Number.isInteger(value)) {
495
+ return false;
496
+ }
497
+ return allowNegative || value >= 0;
498
+ }
499
+ if (typeof value === "string") {
500
+ if (value.length === 0) {
501
+ return false;
502
+ }
503
+ const pattern = allowNegative ? /^-?\d+$/ : /^\d+$/;
504
+ return pattern.test(value);
505
+ }
506
+ return false;
507
+ }
508
+ function isHex(value) {
509
+ return typeof value === "string" && /^0x[0-9a-fA-F]*$/.test(value);
510
+ }
511
+ function validateFieldValue(type, value) {
512
+ const normalizedType = type.trim().toLowerCase();
513
+ const bytesNMatch = normalizedType.match(/^bytes([1-9]|[12]\d|3[0-2])$/);
514
+ if (/^uint\d*$/.test(normalizedType)) {
515
+ return isNumericValue(value, false);
516
+ }
517
+ if (/^int\d*$/.test(normalizedType)) {
518
+ return isNumericValue(value, true);
519
+ }
520
+ if (normalizedType === "string") {
521
+ return typeof value === "string";
522
+ }
523
+ if (normalizedType === "string[]") {
524
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
525
+ }
526
+ if (normalizedType === "bool") {
527
+ return typeof value === "boolean";
528
+ }
529
+ if (normalizedType === "address") {
530
+ return typeof value === "string" && ethers.isAddress(value);
531
+ }
532
+ if (normalizedType === "bytes") {
533
+ return isHex(value) && (value.length - 2) % 2 === 0;
534
+ }
535
+ if (bytesNMatch) {
536
+ const expectedBytes = Number(bytesNMatch[1]);
537
+ return isHex(value) && value.length === 2 + expectedBytes * 2;
538
+ }
539
+ return true;
540
+ }
541
+ function validateAttestationData(schema, data) {
542
+ if (!data || typeof data !== "object") {
543
+ return [{
544
+ schemaFieldName: "data",
545
+ expectedType: "object",
546
+ providedType: getActualType(data),
547
+ providedValue: data
548
+ }];
549
+ }
550
+ const fields = normalizeSchema(schema);
551
+ const errors = [];
552
+ for (const field of fields) {
553
+ const value = data[field.name];
554
+ const isValid = validateFieldValue(field.type, value);
555
+ if (isValid) {
556
+ continue;
557
+ }
558
+ errors.push({
559
+ schemaFieldName: field.name,
560
+ expectedType: field.type,
561
+ providedType: getActualType(value),
562
+ providedValue: value
563
+ });
564
+ }
565
+ return errors;
566
+ }
460
567
  function decodeAttestationData(schema, encodedData) {
461
568
  if (typeof encodedData !== "string" || !encodedData.startsWith("0x")) {
462
569
  throw new OmaTrustError("INVALID_INPUT", "encodedData must be a hex string");
@@ -477,22 +584,11 @@ function decodeAttestationData(schema, encodedData) {
477
584
  return result;
478
585
  }
479
586
  function extractExpirationTime(data) {
480
- const keys = ["expirationTime", "expiration", "validUntil", "expiresAt", "expires"];
481
- for (const key of keys) {
482
- const value = data[key];
483
- if (value === void 0 || value === null) {
484
- continue;
485
- }
486
- if (typeof value === "bigint") {
487
- return value;
488
- }
489
- if (typeof value === "number") {
490
- return value;
491
- }
492
- if (typeof value === "string" && /^\d+$/.test(value)) {
493
- return BigInt(value);
494
- }
495
- }
587
+ const value = data["expiresAt"];
588
+ if (value === void 0 || value === null) return void 0;
589
+ if (typeof value === "bigint") return value;
590
+ if (typeof value === "number") return value;
591
+ if (typeof value === "string" && /^\d+$/.test(value)) return BigInt(value);
496
592
  return void 0;
497
593
  }
498
594
  var ZERO_UID = "0x0000000000000000000000000000000000000000000000000000000000000000";
@@ -533,6 +629,53 @@ function resolveRecipientAddress(data) {
533
629
  return ethers.ZeroAddress;
534
630
  }
535
631
 
632
+ // src/reputation/eas-adapter.ts
633
+ function isRecord(value) {
634
+ return Boolean(value) && typeof value === "object";
635
+ }
636
+ function isHex32(value) {
637
+ return typeof value === "string" && /^0x[0-9a-fA-F]{64}$/.test(value);
638
+ }
639
+ function getEasTransactionReceipt(tx) {
640
+ if (!isRecord(tx)) {
641
+ return void 0;
642
+ }
643
+ const candidates = [tx.receipt, tx.tx, tx.transaction];
644
+ for (const candidate of candidates) {
645
+ if (isRecord(candidate)) {
646
+ return candidate;
647
+ }
648
+ }
649
+ return void 0;
650
+ }
651
+ function getEasTransactionHash(tx) {
652
+ const receipt = getEasTransactionReceipt(tx);
653
+ if (receipt) {
654
+ const receiptHash = receipt.hash;
655
+ if (isHex32(receiptHash)) {
656
+ return receiptHash;
657
+ }
658
+ const transactionHash = receipt.transactionHash;
659
+ if (isHex32(transactionHash)) {
660
+ return transactionHash;
661
+ }
662
+ }
663
+ if (isRecord(tx) && isHex32(tx.hash)) {
664
+ return tx.hash;
665
+ }
666
+ return void 0;
667
+ }
668
+ function isEasSchemaNotFoundError(err) {
669
+ if (!isRecord(err)) {
670
+ return false;
671
+ }
672
+ const message = err.message;
673
+ if (typeof message !== "string" || message.length === 0) {
674
+ return false;
675
+ }
676
+ return /schema not found/i.test(message);
677
+ }
678
+
536
679
  // src/reputation/submit.ts
537
680
  async function submitAttestation(params) {
538
681
  if (!params || typeof params !== "object") {
@@ -563,25 +706,46 @@ async function submitAttestation(params) {
563
706
  }
564
707
  });
565
708
  const uid = await tx.wait();
566
- const txAny = tx;
567
- const txHash = txAny.tx?.hash ?? txAny.hash ?? txAny.transaction?.hash ?? ZERO_UID;
709
+ const txHash = getEasTransactionHash(tx) ?? ZERO_UID;
710
+ const receipt = getEasTransactionReceipt(tx);
568
711
  return {
569
712
  uid,
570
713
  txHash,
571
- receipt: txAny.tx
714
+ receipt
572
715
  };
573
716
  } catch (err) {
574
717
  throw new OmaTrustError("NETWORK_ERROR", "Failed to submit attestation", { err });
575
718
  }
576
719
  }
577
- function buildDelegatedAttestationTypedData(params) {
578
- const dataWithHash = withAutoSubjectDidHash(params.schema, params.data);
579
- const encodedData = encodeAttestationData(params.schema, dataWithHash);
580
- const recipient = resolveRecipientAddress(dataWithHash);
581
- const expiration = toBigIntOrDefault(
582
- params.expirationTime ?? extractExpirationTime(dataWithHash),
583
- 0n
584
- );
720
+ async function revokeAttestation(params) {
721
+ if (!params || typeof params !== "object") {
722
+ throw new OmaTrustError("INVALID_INPUT", "params must be provided");
723
+ }
724
+ if (!params.signer) {
725
+ throw new OmaTrustError("INVALID_INPUT", "signer is required");
726
+ }
727
+ const eas = new easSdk.EAS(params.easContractAddress);
728
+ eas.connect(params.signer);
729
+ try {
730
+ const tx = await eas.revoke({
731
+ schema: params.schemaUid,
732
+ data: {
733
+ uid: params.uid,
734
+ value: toBigIntOrDefault(params.value, 0n)
735
+ }
736
+ });
737
+ await tx.wait();
738
+ const txHash = getEasTransactionHash(tx) ?? ZERO_UID;
739
+ const receipt = getEasTransactionReceipt(tx);
740
+ return {
741
+ txHash,
742
+ receipt
743
+ };
744
+ } catch (err) {
745
+ throw new OmaTrustError("NETWORK_ERROR", "Failed to revoke attestation", { err });
746
+ }
747
+ }
748
+ function buildDelegatedTypedData(params) {
585
749
  return {
586
750
  domain: {
587
751
  name: "EAS",
@@ -606,17 +770,52 @@ function buildDelegatedAttestationTypedData(params) {
606
770
  message: {
607
771
  attester: params.attester,
608
772
  schema: params.schemaUid,
609
- recipient,
610
- expirationTime: expiration,
773
+ recipient: params.recipient,
774
+ expirationTime: toBigIntOrDefault(params.expirationTime, 0n),
611
775
  revocable: params.revocable ?? true,
612
776
  refUID: params.refUid ?? ZERO_UID,
613
- data: encodedData,
777
+ data: params.encodedData,
614
778
  value: toBigIntOrDefault(params.value, 0n),
615
779
  nonce: toBigIntOrDefault(params.nonce, 0n),
616
780
  deadline: toBigIntOrDefault(params.deadline, BigInt(Math.floor(Date.now() / 1e3) + 600))
617
781
  }
618
782
  };
619
783
  }
784
+ function buildDelegatedAttestationTypedData(params) {
785
+ const dataWithHash = withAutoSubjectDidHash(params.schema, params.data);
786
+ const encodedData = encodeAttestationData(params.schema, dataWithHash);
787
+ const recipient = resolveRecipientAddress(dataWithHash);
788
+ return buildDelegatedTypedData({
789
+ chainId: params.chainId,
790
+ easContractAddress: params.easContractAddress,
791
+ schemaUid: params.schemaUid,
792
+ encodedData,
793
+ recipient,
794
+ attester: params.attester,
795
+ nonce: params.nonce,
796
+ revocable: params.revocable,
797
+ expirationTime: params.expirationTime ?? extractExpirationTime(dataWithHash),
798
+ refUid: params.refUid,
799
+ value: params.value,
800
+ deadline: params.deadline
801
+ });
802
+ }
803
+ function buildDelegatedTypedDataFromEncoded(params) {
804
+ return buildDelegatedTypedData({
805
+ chainId: params.chainId,
806
+ easContractAddress: params.easContractAddress,
807
+ schemaUid: params.schemaUid,
808
+ encodedData: params.encodedData,
809
+ recipient: params.recipient,
810
+ attester: params.attester,
811
+ nonce: params.nonce,
812
+ revocable: params.revocable,
813
+ expirationTime: params.expirationTime,
814
+ refUid: params.refUid,
815
+ value: params.value,
816
+ deadline: params.deadline
817
+ });
818
+ }
620
819
  function splitSignature(signature) {
621
820
  try {
622
821
  const parsed = ethers.Signature.from(signature);
@@ -693,7 +892,14 @@ async function submitDelegatedAttestation(params) {
693
892
  var EAS_EVENT_ABI = [
694
893
  "event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID)"
695
894
  ];
696
- function parseAttestation(attestation, schema) {
895
+ function parseEventTxHash(event) {
896
+ const txHash = event.transactionHash;
897
+ if (typeof txHash !== "string") {
898
+ return void 0;
899
+ }
900
+ return /^0x[0-9a-fA-F]{64}$/.test(txHash) ? txHash : void 0;
901
+ }
902
+ function parseAttestation(attestation, schema, txHash) {
697
903
  const rawData = attestation.data ?? "0x";
698
904
  const decoded = schema ? decodeAttestationData(schema, rawData) : {};
699
905
  const toBigIntSafe = (value) => {
@@ -713,6 +919,7 @@ function parseAttestation(attestation, schema) {
713
919
  schema: attestation.schema,
714
920
  attester: attestation.attester,
715
921
  recipient: attestation.recipient,
922
+ txHash,
716
923
  revocable: Boolean(attestation.revocable),
717
924
  revocationTime: toBigIntSafe(attestation.revocationTime),
718
925
  expirationTime: toBigIntSafe(attestation.expirationTime),
@@ -738,21 +945,18 @@ async function getAttestation(params) {
738
945
  throw new OmaTrustError("NETWORK_ERROR", "Failed to read attestation", { err });
739
946
  }
740
947
  }
741
- async function getAttestationsForDid(params) {
742
- const provider = params.provider;
743
- const contract = new ethers.Contract(params.easContractAddress, EAS_EVENT_ABI, provider);
744
- const toBlock = params.toBlock ?? await provider.getBlockNumber();
745
- const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
746
- const filter = contract.filters.Attested(didToAddress(params.did));
948
+ async function queryAttestationEvents(easContractAddress, provider, fromBlock, toBlock, options) {
949
+ const contract = new ethers.Contract(easContractAddress, EAS_EVENT_ABI, provider);
950
+ const filter = contract.filters.Attested(options?.recipient ?? null, options?.attester ?? null);
747
951
  let events;
748
952
  try {
749
953
  events = await contract.queryFilter(filter, fromBlock, toBlock);
750
954
  } catch (err) {
751
955
  throw new OmaTrustError("NETWORK_ERROR", "Failed to query attestation events", { err });
752
956
  }
753
- const eas = new easSdk.EAS(params.easContractAddress);
957
+ const eas = new easSdk.EAS(easContractAddress);
754
958
  eas.connect(provider);
755
- const schemaFilter = params.schemas?.map((schema) => schema.toLowerCase());
959
+ const schemaFilter = options?.schemas?.map((s) => s.toLowerCase());
756
960
  const results = [];
757
961
  for (const event of events) {
758
962
  if (!("args" in event && Array.isArray(event.args))) {
@@ -771,11 +975,39 @@ async function getAttestationsForDid(params) {
771
975
  if (!attestation || !attestation.uid) {
772
976
  continue;
773
977
  }
774
- results.push(parseAttestation(attestation));
978
+ results.push(parseAttestation(attestation, void 0, parseEventTxHash(event)));
775
979
  }
776
980
  results.sort((a, b) => Number(b.time - a.time));
777
981
  return results;
778
982
  }
983
+ async function getAttestationsForDid(params) {
984
+ const provider = params.provider;
985
+ const toBlock = params.toBlock ?? await provider.getBlockNumber();
986
+ const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
987
+ return queryAttestationEvents(
988
+ params.easContractAddress,
989
+ provider,
990
+ fromBlock,
991
+ toBlock,
992
+ { recipient: didToAddress(params.did), schemas: params.schemas }
993
+ );
994
+ }
995
+ async function getAttestationsByAttester(params) {
996
+ const provider = params.provider;
997
+ const toBlock = params.toBlock ?? await provider.getBlockNumber();
998
+ const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
999
+ if (params.limit !== void 0 && params.limit <= 0) {
1000
+ return [];
1001
+ }
1002
+ const results = await queryAttestationEvents(
1003
+ params.easContractAddress,
1004
+ provider,
1005
+ fromBlock,
1006
+ toBlock,
1007
+ { attester: params.attester, schemas: params.schemas }
1008
+ );
1009
+ return params.limit !== void 0 ? results.slice(0, params.limit) : results;
1010
+ }
779
1011
  async function listAttestations(params) {
780
1012
  const limit = params.limit ?? 20;
781
1013
  if (limit <= 0) {
@@ -786,34 +1018,15 @@ async function listAttestations(params) {
786
1018
  }
787
1019
  async function getLatestAttestations(params) {
788
1020
  const provider = params.provider;
789
- const contract = new ethers.Contract(params.easContractAddress, EAS_EVENT_ABI, provider);
790
- const currentBlock = await provider.getBlockNumber();
791
- const fromBlock = params.fromBlock ?? Math.max(0, currentBlock - 5e4);
792
- const events = await contract.queryFilter(contract.filters.Attested(), fromBlock, currentBlock);
793
- const eas = new easSdk.EAS(params.easContractAddress);
794
- eas.connect(provider);
795
- const schemaFilter = params.schemas?.map((schema) => schema.toLowerCase());
796
- const results = [];
797
- for (const event of events) {
798
- if (!("args" in event && Array.isArray(event.args))) {
799
- continue;
800
- }
801
- const args = event.args;
802
- const uid = args?.[2];
803
- const schemaUid = args?.[3];
804
- if (!uid || !schemaUid) {
805
- continue;
806
- }
807
- if (schemaFilter && !schemaFilter.includes(schemaUid.toLowerCase())) {
808
- continue;
809
- }
810
- const attestation = await eas.getAttestation(uid);
811
- if (!attestation || !attestation.uid) {
812
- continue;
813
- }
814
- results.push(parseAttestation(attestation));
815
- }
816
- results.sort((a, b) => Number(b.time - a.time));
1021
+ const toBlock = await provider.getBlockNumber();
1022
+ const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
1023
+ const results = await queryAttestationEvents(
1024
+ params.easContractAddress,
1025
+ provider,
1026
+ fromBlock,
1027
+ toBlock,
1028
+ { schemas: params.schemas }
1029
+ );
817
1030
  return results.slice(0, params.limit ?? 20);
818
1031
  }
819
1032
  function deduplicateReviews(attestations) {
@@ -1075,6 +1288,13 @@ function verifyDidDocumentControllerDid(didDocument, expectedControllerDid) {
1075
1288
  reason: `No matching address found in DID document (expected ${expectedAddress})`
1076
1289
  };
1077
1290
  }
1291
+ async function verifyDidJsonControllerDid(domain, expectedControllerDid, options = {}) {
1292
+ if (!domain || typeof domain !== "string") {
1293
+ throw new OmaTrustError("INVALID_INPUT", "domain must be a non-empty string", { domain });
1294
+ }
1295
+ const didDocument = options.fetchDidDocument ? await options.fetchDidDocument(domain) : await fetchDidDocument(domain);
1296
+ return verifyDidDocumentControllerDid(didDocument, expectedControllerDid);
1297
+ }
1078
1298
  function buildEip712Domain(name, version, chainId, verifyingContract) {
1079
1299
  return { name, version, chainId, verifyingContract };
1080
1300
  }
@@ -1107,6 +1327,8 @@ function verifyEip712Signature(typedData, signature) {
1107
1327
  throw new OmaTrustError("INVALID_INPUT", "Failed to verify EIP-712 signature", { err });
1108
1328
  }
1109
1329
  }
1330
+
1331
+ // src/reputation/proof/dns-txt-record.ts
1110
1332
  function parseDnsTxtRecord(record) {
1111
1333
  if (!record || typeof record !== "string") {
1112
1334
  throw new OmaTrustError("INVALID_INPUT", "record must be a non-empty string", { record });
@@ -1134,27 +1356,6 @@ function buildDnsTxtRecord(controllerDid) {
1134
1356
  const normalized = normalizeDid(controllerDid);
1135
1357
  return `v=1;controller=${normalized}`;
1136
1358
  }
1137
- async function verifyDnsTxtControllerDid(domain, expectedControllerDid) {
1138
- if (!domain || typeof domain !== "string") {
1139
- throw new OmaTrustError("INVALID_INPUT", "domain must be a non-empty string", { domain });
1140
- }
1141
- const expected = normalizeDid(expectedControllerDid);
1142
- const host = `_omatrust.${domain.toLowerCase().replace(/\.$/, "")}`;
1143
- let records;
1144
- try {
1145
- records = await promises.resolveTxt(host);
1146
- } catch (err) {
1147
- throw new OmaTrustError("NETWORK_ERROR", "Failed to resolve DNS TXT records", { domain, err });
1148
- }
1149
- for (const recordParts of records) {
1150
- const record = recordParts.join("");
1151
- const parsed = parseDnsTxtRecord(record);
1152
- if (parsed.version === "1" && parsed.controller && normalizeDid(parsed.controller) === expected) {
1153
- return { valid: true, record };
1154
- }
1155
- }
1156
- return { valid: false, reason: "No TXT record matched expected controller DID" };
1157
- }
1158
1359
 
1159
1360
  // src/reputation/verify.ts
1160
1361
  function parseChainId(input) {
@@ -1435,6 +1636,9 @@ async function getSchemaDetails(schemaRegistry, schemaUid) {
1435
1636
  revocable: Boolean(details.revocable)
1436
1637
  };
1437
1638
  } catch (err) {
1639
+ if (isEasSchemaNotFoundError(err)) {
1640
+ throw new OmaTrustError("SCHEMA_NOT_FOUND", "Schema was not found", { schemaUid });
1641
+ }
1438
1642
  if (err instanceof OmaTrustError) {
1439
1643
  throw err;
1440
1644
  }
@@ -1618,6 +1822,366 @@ function createEvidencePointerProof(url) {
1618
1822
  issuedAt: Math.floor(Date.now() / 1e3)
1619
1823
  };
1620
1824
  }
1825
+ async function verifyDnsTxtControllerDid(domain, expectedControllerDid, options = {}) {
1826
+ if (!domain || typeof domain !== "string") {
1827
+ throw new OmaTrustError("INVALID_INPUT", "domain must be a non-empty string", { domain });
1828
+ }
1829
+ const expected = normalizeDid(expectedControllerDid);
1830
+ const prefix = options.recordPrefix ?? "_controllers";
1831
+ const host = `${prefix}.${domain.toLowerCase().replace(/\.$/, "")}`;
1832
+ let records;
1833
+ try {
1834
+ records = await (options.resolveTxt ?? promises.resolveTxt)(host);
1835
+ } catch (err) {
1836
+ throw new OmaTrustError("NETWORK_ERROR", "Failed to resolve DNS TXT records", { domain, err });
1837
+ }
1838
+ for (const recordParts of records) {
1839
+ const record = recordParts.join("");
1840
+ const parsed = parseDnsTxtRecord(record);
1841
+ if (parsed.version === "1" && parsed.controller && normalizeDid(parsed.controller) === expected) {
1842
+ return { valid: true, record };
1843
+ }
1844
+ }
1845
+ return { valid: false, reason: "No TXT record matched expected controller DID" };
1846
+ }
1847
+
1848
+ // src/reputation/proof/dns-txt-shared.ts
1849
+ async function verifyDnsTxtControllerDid2(domain, expectedControllerDid, options = {}) {
1850
+ if (!domain || typeof domain !== "string") {
1851
+ throw new OmaTrustError("INVALID_INPUT", "domain must be a non-empty string", { domain });
1852
+ }
1853
+ if (!options.resolveTxt) {
1854
+ throw new OmaTrustError("NETWORK_ERROR", "No DNS TXT resolver was provided", { domain });
1855
+ }
1856
+ const expected = normalizeDid(expectedControllerDid);
1857
+ const prefix = options.recordPrefix ?? "_controllers";
1858
+ const host = `${prefix}.${domain.toLowerCase().replace(/\.$/, "")}`;
1859
+ let records;
1860
+ try {
1861
+ records = await options.resolveTxt(host);
1862
+ } catch (err) {
1863
+ throw new OmaTrustError("NETWORK_ERROR", "Failed to resolve DNS TXT records", { domain, err });
1864
+ }
1865
+ for (const recordParts of records) {
1866
+ const record = recordParts.join("");
1867
+ const parsed = parseDnsTxtRecord(record);
1868
+ if (parsed.version === "1" && parsed.controller && normalizeDid(parsed.controller) === expected) {
1869
+ return { valid: true, record };
1870
+ }
1871
+ }
1872
+ return { valid: false, reason: "No TXT record matched expected controller DID" };
1873
+ }
1874
+
1875
+ // src/reputation/proof/subject-ownership.ts
1876
+ var EIP1967_ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
1877
+ var OWNERSHIP_PATTERNS = [
1878
+ { method: "owner", signature: "function owner() view returns (address)" },
1879
+ { method: "admin", signature: "function admin() view returns (address)" },
1880
+ { method: "getOwner", signature: "function getOwner() view returns (address)" }
1881
+ ];
1882
+ function assertConnectedWalletDid(input) {
1883
+ const normalized = normalizeDid(input);
1884
+ if (extractDidMethod(normalized) !== "pkh") {
1885
+ throw new OmaTrustError("INVALID_INPUT", "connectedWalletDid must be a did:pkh DID", {
1886
+ connectedWalletDid: input
1887
+ });
1888
+ }
1889
+ return normalized;
1890
+ }
1891
+ function normalizeSubjectDid(input) {
1892
+ return normalizeDid(input);
1893
+ }
1894
+ async function readAddressFromContract(provider, contractAddress, signature, method) {
1895
+ try {
1896
+ const iface = new ethers.Interface([signature]);
1897
+ const data = iface.encodeFunctionData(method, []);
1898
+ const result = await provider.call({ to: contractAddress, data });
1899
+ const [value] = iface.decodeFunctionResult(method, result);
1900
+ if (typeof value === "string" && ethers.isAddress(value) && value !== ethers.ZeroAddress) {
1901
+ return ethers.getAddress(value);
1902
+ }
1903
+ } catch {
1904
+ }
1905
+ return null;
1906
+ }
1907
+ async function discoverControllingWallet(provider, contractAddress, chainId) {
1908
+ for (const pattern of OWNERSHIP_PATTERNS) {
1909
+ const address = await readAddressFromContract(
1910
+ provider,
1911
+ contractAddress,
1912
+ pattern.signature,
1913
+ pattern.method
1914
+ );
1915
+ if (address) {
1916
+ return buildEvmDidPkh(chainId, address);
1917
+ }
1918
+ }
1919
+ try {
1920
+ const adminValue = await provider.getStorage(contractAddress, EIP1967_ADMIN_SLOT);
1921
+ if (adminValue && adminValue !== "0x" && adminValue !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
1922
+ const adminAddress = ethers.getAddress(`0x${adminValue.slice(-40)}`);
1923
+ if (adminAddress !== ethers.ZeroAddress) {
1924
+ return buildEvmDidPkh(chainId, adminAddress);
1925
+ }
1926
+ }
1927
+ } catch {
1928
+ }
1929
+ return null;
1930
+ }
1931
+ async function verifyDidWebOwnership(params) {
1932
+ const subjectDid = normalizeSubjectDid(params.subjectDid);
1933
+ const connectedWalletDid = assertConnectedWalletDid(params.connectedWalletDid);
1934
+ const domain = getDomainFromDidWeb(subjectDid);
1935
+ if (!domain) {
1936
+ throw new OmaTrustError("INVALID_INPUT", "subjectDid must be a did:web DID", {
1937
+ subjectDid: params.subjectDid
1938
+ });
1939
+ }
1940
+ let dnsReason;
1941
+ try {
1942
+ const dnsResult = await verifyDnsTxtControllerDid2(domain, connectedWalletDid, {
1943
+ resolveTxt: params.resolveTxt,
1944
+ recordPrefix: params.recordPrefix
1945
+ });
1946
+ if (dnsResult.valid) {
1947
+ return {
1948
+ valid: true,
1949
+ method: "dns",
1950
+ details: `Verified via DNS TXT record at ${params.recordPrefix ?? "_controllers"}.${domain}`,
1951
+ subjectDid,
1952
+ connectedWalletDid
1953
+ };
1954
+ }
1955
+ dnsReason = dnsResult.reason;
1956
+ } catch (error) {
1957
+ dnsReason = error instanceof Error ? error.message : "DNS TXT verification failed";
1958
+ }
1959
+ let didDocReason;
1960
+ try {
1961
+ const didDocumentResult = await verifyDidJsonControllerDid(domain, connectedWalletDid, {
1962
+ fetchDidDocument: params.fetchDidDocument
1963
+ });
1964
+ if (didDocumentResult.valid) {
1965
+ return {
1966
+ valid: true,
1967
+ method: "did-document",
1968
+ details: `Verified via DID document at https://${domain}/.well-known/did.json`,
1969
+ subjectDid,
1970
+ connectedWalletDid
1971
+ };
1972
+ }
1973
+ didDocReason = didDocumentResult.reason;
1974
+ } catch (error) {
1975
+ didDocReason = error instanceof Error ? error.message : "DID document verification failed";
1976
+ }
1977
+ return {
1978
+ valid: false,
1979
+ reason: "DID ownership verification failed",
1980
+ details: `DNS check: ${dnsReason ?? "failed"}. DID document check: ${didDocReason ?? "failed"}.`,
1981
+ subjectDid,
1982
+ connectedWalletDid
1983
+ };
1984
+ }
1985
+ async function verifyDidPkhOwnership(params) {
1986
+ const subjectDid = normalizeSubjectDid(params.subjectDid);
1987
+ const connectedWalletDid = assertConnectedWalletDid(params.connectedWalletDid);
1988
+ if (!isEvmDidPkh(subjectDid)) {
1989
+ throw new OmaTrustError("INVALID_INPUT", "subjectDid must be an EVM did:pkh DID", {
1990
+ subjectDid: params.subjectDid
1991
+ });
1992
+ }
1993
+ const subjectAddress = getAddressFromDidPkh(subjectDid);
1994
+ const connectedWalletAddress = getAddressFromDidPkh(connectedWalletDid);
1995
+ const chainIdRaw = getChainIdFromDidPkh(subjectDid);
1996
+ if (!subjectAddress || !connectedWalletAddress || !chainIdRaw) {
1997
+ throw new OmaTrustError("INVALID_INPUT", "Could not parse did:pkh ownership inputs", {
1998
+ subjectDid: params.subjectDid,
1999
+ connectedWalletDid: params.connectedWalletDid
2000
+ });
2001
+ }
2002
+ const chainId = Number(chainIdRaw);
2003
+ if (!Number.isFinite(chainId)) {
2004
+ throw new OmaTrustError("INVALID_INPUT", "Invalid chain id in subjectDid", {
2005
+ subjectDid: params.subjectDid
2006
+ });
2007
+ }
2008
+ const code = await params.provider.getCode(subjectAddress);
2009
+ const isContract = code !== "0x" && code !== "0x0";
2010
+ if (!isContract) {
2011
+ if (ethers.getAddress(subjectAddress) === ethers.getAddress(connectedWalletAddress)) {
2012
+ return {
2013
+ valid: true,
2014
+ method: "wallet",
2015
+ details: "Verified direct wallet ownership from matching did:pkh subject and connected wallet",
2016
+ subjectDid,
2017
+ connectedWalletDid
2018
+ };
2019
+ }
2020
+ return {
2021
+ valid: false,
2022
+ reason: "EOA did:pkh subject does not match connected wallet",
2023
+ details: "For direct wallet did:pkh subjects, connectedWalletDid must match the subject DID.",
2024
+ subjectDid,
2025
+ connectedWalletDid
2026
+ };
2027
+ }
2028
+ const controllingWalletDid = await discoverControllingWallet(params.provider, subjectAddress, chainId);
2029
+ if (params.txHash) {
2030
+ if (!controllingWalletDid) {
2031
+ return {
2032
+ valid: false,
2033
+ reason: "Could not discover controlling wallet",
2034
+ details: "Contract does not expose owner/admin/getOwner or a readable EIP-1967 admin slot for transfer verification.",
2035
+ subjectDid,
2036
+ connectedWalletDid
2037
+ };
2038
+ }
2039
+ const tx = await params.provider.getTransaction(params.txHash);
2040
+ if (!tx) {
2041
+ return {
2042
+ valid: false,
2043
+ reason: "Transaction not found",
2044
+ details: `Transaction ${params.txHash} was not found on chain ${chainId}.`,
2045
+ subjectDid,
2046
+ connectedWalletDid,
2047
+ controllingWalletDid
2048
+ };
2049
+ }
2050
+ const receipt = await params.provider.getTransactionReceipt(params.txHash);
2051
+ if (!receipt) {
2052
+ return {
2053
+ valid: false,
2054
+ reason: "Transaction not confirmed",
2055
+ details: "Transaction exists but is not yet confirmed.",
2056
+ subjectDid,
2057
+ connectedWalletDid,
2058
+ controllingWalletDid
2059
+ };
2060
+ }
2061
+ const controllingWalletAddress = getAddressFromDidPkh(controllingWalletDid);
2062
+ if (!tx.from || !controllingWalletAddress || ethers.getAddress(tx.from) !== ethers.getAddress(controllingWalletAddress)) {
2063
+ return {
2064
+ valid: false,
2065
+ reason: "Wrong sender",
2066
+ details: `Transfer must originate from controlling wallet ${controllingWalletDid}.`,
2067
+ subjectDid,
2068
+ connectedWalletDid,
2069
+ controllingWalletDid
2070
+ };
2071
+ }
2072
+ if (!tx.to || ethers.getAddress(tx.to) !== ethers.getAddress(connectedWalletAddress)) {
2073
+ return {
2074
+ valid: false,
2075
+ reason: "Wrong recipient",
2076
+ details: `Transfer must be sent to connected wallet ${connectedWalletDid}.`,
2077
+ subjectDid,
2078
+ connectedWalletDid,
2079
+ controllingWalletDid
2080
+ };
2081
+ }
2082
+ const expectedAmount = calculateTransferAmount(
2083
+ subjectDid,
2084
+ connectedWalletDid,
2085
+ chainId,
2086
+ "shared-control"
2087
+ );
2088
+ const actualValue = BigInt(tx.value ?? 0n);
2089
+ if (actualValue !== expectedAmount) {
2090
+ return {
2091
+ valid: false,
2092
+ reason: "Wrong amount",
2093
+ details: `Transfer amount ${actualValue.toString()} does not match expected proof amount ${expectedAmount.toString()}.`,
2094
+ subjectDid,
2095
+ connectedWalletDid,
2096
+ controllingWalletDid
2097
+ };
2098
+ }
2099
+ await params.provider.getBlockNumber();
2100
+ await params.provider.getBlock(receipt.blockNumber);
2101
+ return {
2102
+ valid: true,
2103
+ method: "transfer",
2104
+ details: `Verified via transfer proof ${params.txHash}.`,
2105
+ subjectDid,
2106
+ connectedWalletDid,
2107
+ controllingWalletDid
2108
+ };
2109
+ }
2110
+ for (const pattern of OWNERSHIP_PATTERNS) {
2111
+ const ownerAddress = await readAddressFromContract(
2112
+ params.provider,
2113
+ subjectAddress,
2114
+ pattern.signature,
2115
+ pattern.method
2116
+ );
2117
+ if (ownerAddress && ethers.getAddress(ownerAddress) === ethers.getAddress(connectedWalletAddress)) {
2118
+ return {
2119
+ valid: true,
2120
+ method: "contract",
2121
+ details: `Verified via ${pattern.method}() ownership check.`,
2122
+ subjectDid,
2123
+ connectedWalletDid,
2124
+ controllingWalletDid: controllingWalletDid ?? void 0
2125
+ };
2126
+ }
2127
+ }
2128
+ try {
2129
+ const adminValue = await params.provider.getStorage(subjectAddress, EIP1967_ADMIN_SLOT);
2130
+ if (adminValue && adminValue !== "0x" && adminValue !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
2131
+ const adminAddress = ethers.getAddress(`0x${adminValue.slice(-40)}`);
2132
+ if (adminAddress === ethers.getAddress(connectedWalletAddress)) {
2133
+ return {
2134
+ valid: true,
2135
+ method: "contract",
2136
+ details: "Verified via EIP-1967 admin slot.",
2137
+ subjectDid,
2138
+ connectedWalletDid,
2139
+ controllingWalletDid: controllingWalletDid ?? buildEvmDidPkh(chainId, adminAddress)
2140
+ };
2141
+ }
2142
+ }
2143
+ } catch {
2144
+ }
2145
+ if (ethers.getAddress(subjectAddress) === ethers.getAddress(connectedWalletAddress) && controllingWalletDid) {
2146
+ return {
2147
+ valid: true,
2148
+ method: "minting-wallet",
2149
+ details: `Verified because connected wallet matches the contract DID address. Controlling wallet is ${controllingWalletDid}.`,
2150
+ subjectDid,
2151
+ connectedWalletDid,
2152
+ controllingWalletDid
2153
+ };
2154
+ }
2155
+ return {
2156
+ valid: false,
2157
+ reason: "Contract ownership verification failed",
2158
+ details: controllingWalletDid ? `Connected wallet ${connectedWalletDid} does not match the controlling wallet ${controllingWalletDid} or the subject contract address ${subjectDid}.` : `Could not match connected wallet ${connectedWalletDid} to contract ownership for ${subjectDid}.`,
2159
+ subjectDid,
2160
+ connectedWalletDid,
2161
+ controllingWalletDid: controllingWalletDid ?? void 0
2162
+ };
2163
+ }
2164
+ async function verifySubjectOwnership(params) {
2165
+ const subjectDid = normalizeSubjectDid(params.subjectDid);
2166
+ const method = extractDidMethod(subjectDid);
2167
+ if (method === "web") {
2168
+ return verifyDidWebOwnership(params);
2169
+ }
2170
+ if (method === "pkh") {
2171
+ const didPkhParams = params;
2172
+ if (!didPkhParams.provider) {
2173
+ throw new OmaTrustError(
2174
+ "INVALID_INPUT",
2175
+ "provider is required for did:pkh ownership verification",
2176
+ { subjectDid }
2177
+ );
2178
+ }
2179
+ return verifyDidPkhOwnership(didPkhParams);
2180
+ }
2181
+ throw new OmaTrustError("INVALID_INPUT", "Unsupported DID type for ownership verification", {
2182
+ subjectDid
2183
+ });
2184
+ }
1621
2185
 
1622
2186
  // src/app-registry/index.ts
1623
2187
  var app_registry_exports = {};