@oma3/omatrust 0.1.0-alpha.1 → 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 +21 -7
  2. package/dist/identity/index.cjs +1 -1
  3. package/dist/identity/index.cjs.map +1 -1
  4. package/dist/identity/index.js +1 -1
  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 +656 -91
  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 +657 -92
  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 +675 -90
  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 +669 -92
  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");
@@ -361,6 +361,7 @@ function hashCanonicalizedJson(obj, algorithm) {
361
361
  var reputation_exports = {};
362
362
  __export(reputation_exports, {
363
363
  buildDelegatedAttestationTypedData: () => buildDelegatedAttestationTypedData,
364
+ buildDelegatedTypedDataFromEncoded: () => buildDelegatedTypedDataFromEncoded,
364
365
  buildDnsTxtRecord: () => buildDnsTxtRecord,
365
366
  buildEip712Domain: () => buildEip712Domain,
366
367
  calculateAverageUserReviewRating: () => calculateAverageUserReviewRating,
@@ -384,6 +385,7 @@ __export(reputation_exports, {
384
385
  formatSchemaUid: () => formatSchemaUid,
385
386
  formatTransferAmount: () => formatTransferAmount,
386
387
  getAttestation: () => getAttestation,
388
+ getAttestationsByAttester: () => getAttestationsByAttester,
387
389
  getAttestationsForDid: () => getAttestationsForDid,
388
390
  getChainConstants: () => getChainConstants,
389
391
  getExplorerAddressUrl: () => getExplorerAddressUrl,
@@ -399,16 +401,22 @@ __export(reputation_exports, {
399
401
  normalizeSchema: () => normalizeSchema,
400
402
  parseDnsTxtRecord: () => parseDnsTxtRecord,
401
403
  prepareDelegatedAttestation: () => prepareDelegatedAttestation,
404
+ revokeAttestation: () => revokeAttestation,
402
405
  schemaToString: () => schemaToString,
403
406
  splitSignature: () => splitSignature,
404
407
  submitAttestation: () => submitAttestation,
405
408
  submitDelegatedAttestation: () => submitDelegatedAttestation,
409
+ validateAttestationData: () => validateAttestationData,
406
410
  verifyAttestation: () => verifyAttestation,
407
411
  verifyDidDocumentControllerDid: () => verifyDidDocumentControllerDid,
412
+ verifyDidJsonControllerDid: () => verifyDidJsonControllerDid,
413
+ verifyDidPkhOwnership: () => verifyDidPkhOwnership,
414
+ verifyDidWebOwnership: () => verifyDidWebOwnership,
408
415
  verifyDnsTxtControllerDid: () => verifyDnsTxtControllerDid,
409
416
  verifyEip712Signature: () => verifyEip712Signature,
410
417
  verifyProof: () => verifyProof,
411
- verifySchemaExists: () => verifySchemaExists
418
+ verifySchemaExists: () => verifySchemaExists,
419
+ verifySubjectOwnership: () => verifySubjectOwnership
412
420
  });
413
421
  function normalizeSchema(schema) {
414
422
  if (Array.isArray(schema)) {
@@ -444,6 +452,13 @@ function encodeAttestationData(schema, data) {
444
452
  if (!data || typeof data !== "object") {
445
453
  throw new OmaTrustError("INVALID_INPUT", "data must be an object");
446
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
+ }
447
462
  const fields = normalizeSchema(schema);
448
463
  const schemaString = schemaToString(fields);
449
464
  const encoder = new easSdk.SchemaEncoder(schemaString);
@@ -456,6 +471,99 @@ function encodeAttestationData(schema, data) {
456
471
  );
457
472
  return encoded;
458
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
+ }
459
567
  function decodeAttestationData(schema, encodedData) {
460
568
  if (typeof encodedData !== "string" || !encodedData.startsWith("0x")) {
461
569
  throw new OmaTrustError("INVALID_INPUT", "encodedData must be a hex string");
@@ -476,22 +584,11 @@ function decodeAttestationData(schema, encodedData) {
476
584
  return result;
477
585
  }
478
586
  function extractExpirationTime(data) {
479
- const keys = ["expirationTime", "expiration", "validUntil", "expiresAt", "expires"];
480
- for (const key of keys) {
481
- const value = data[key];
482
- if (value === void 0 || value === null) {
483
- continue;
484
- }
485
- if (typeof value === "bigint") {
486
- return value;
487
- }
488
- if (typeof value === "number") {
489
- return value;
490
- }
491
- if (typeof value === "string" && /^\d+$/.test(value)) {
492
- return BigInt(value);
493
- }
494
- }
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);
495
592
  return void 0;
496
593
  }
497
594
  var ZERO_UID = "0x0000000000000000000000000000000000000000000000000000000000000000";
@@ -532,6 +629,53 @@ function resolveRecipientAddress(data) {
532
629
  return ethers.ZeroAddress;
533
630
  }
534
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
+
535
679
  // src/reputation/submit.ts
536
680
  async function submitAttestation(params) {
537
681
  if (!params || typeof params !== "object") {
@@ -562,25 +706,46 @@ async function submitAttestation(params) {
562
706
  }
563
707
  });
564
708
  const uid = await tx.wait();
565
- const txAny = tx;
566
- const txHash = txAny.tx?.hash ?? txAny.hash ?? txAny.transaction?.hash ?? ZERO_UID;
709
+ const txHash = getEasTransactionHash(tx) ?? ZERO_UID;
710
+ const receipt = getEasTransactionReceipt(tx);
567
711
  return {
568
712
  uid,
569
713
  txHash,
570
- receipt: txAny.tx
714
+ receipt
571
715
  };
572
716
  } catch (err) {
573
717
  throw new OmaTrustError("NETWORK_ERROR", "Failed to submit attestation", { err });
574
718
  }
575
719
  }
576
- function buildDelegatedAttestationTypedData(params) {
577
- const dataWithHash = withAutoSubjectDidHash(params.schema, params.data);
578
- const encodedData = encodeAttestationData(params.schema, dataWithHash);
579
- const recipient = resolveRecipientAddress(dataWithHash);
580
- const expiration = toBigIntOrDefault(
581
- params.expirationTime ?? extractExpirationTime(dataWithHash),
582
- 0n
583
- );
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) {
584
749
  return {
585
750
  domain: {
586
751
  name: "EAS",
@@ -605,17 +770,52 @@ function buildDelegatedAttestationTypedData(params) {
605
770
  message: {
606
771
  attester: params.attester,
607
772
  schema: params.schemaUid,
608
- recipient,
609
- expirationTime: expiration,
773
+ recipient: params.recipient,
774
+ expirationTime: toBigIntOrDefault(params.expirationTime, 0n),
610
775
  revocable: params.revocable ?? true,
611
776
  refUID: params.refUid ?? ZERO_UID,
612
- data: encodedData,
777
+ data: params.encodedData,
613
778
  value: toBigIntOrDefault(params.value, 0n),
614
779
  nonce: toBigIntOrDefault(params.nonce, 0n),
615
780
  deadline: toBigIntOrDefault(params.deadline, BigInt(Math.floor(Date.now() / 1e3) + 600))
616
781
  }
617
782
  };
618
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
+ }
619
819
  function splitSignature(signature) {
620
820
  try {
621
821
  const parsed = ethers.Signature.from(signature);
@@ -692,7 +892,14 @@ async function submitDelegatedAttestation(params) {
692
892
  var EAS_EVENT_ABI = [
693
893
  "event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID)"
694
894
  ];
695
- 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) {
696
903
  const rawData = attestation.data ?? "0x";
697
904
  const decoded = schema ? decodeAttestationData(schema, rawData) : {};
698
905
  const toBigIntSafe = (value) => {
@@ -712,6 +919,7 @@ function parseAttestation(attestation, schema) {
712
919
  schema: attestation.schema,
713
920
  attester: attestation.attester,
714
921
  recipient: attestation.recipient,
922
+ txHash,
715
923
  revocable: Boolean(attestation.revocable),
716
924
  revocationTime: toBigIntSafe(attestation.revocationTime),
717
925
  expirationTime: toBigIntSafe(attestation.expirationTime),
@@ -737,21 +945,18 @@ async function getAttestation(params) {
737
945
  throw new OmaTrustError("NETWORK_ERROR", "Failed to read attestation", { err });
738
946
  }
739
947
  }
740
- async function getAttestationsForDid(params) {
741
- const provider = params.provider;
742
- const contract = new ethers.Contract(params.easContractAddress, EAS_EVENT_ABI, provider);
743
- const toBlock = params.toBlock ?? await provider.getBlockNumber();
744
- const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
745
- 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);
746
951
  let events;
747
952
  try {
748
953
  events = await contract.queryFilter(filter, fromBlock, toBlock);
749
954
  } catch (err) {
750
955
  throw new OmaTrustError("NETWORK_ERROR", "Failed to query attestation events", { err });
751
956
  }
752
- const eas = new easSdk.EAS(params.easContractAddress);
957
+ const eas = new easSdk.EAS(easContractAddress);
753
958
  eas.connect(provider);
754
- const schemaFilter = params.schemas?.map((schema) => schema.toLowerCase());
959
+ const schemaFilter = options?.schemas?.map((s) => s.toLowerCase());
755
960
  const results = [];
756
961
  for (const event of events) {
757
962
  if (!("args" in event && Array.isArray(event.args))) {
@@ -770,11 +975,39 @@ async function getAttestationsForDid(params) {
770
975
  if (!attestation || !attestation.uid) {
771
976
  continue;
772
977
  }
773
- results.push(parseAttestation(attestation));
978
+ results.push(parseAttestation(attestation, void 0, parseEventTxHash(event)));
774
979
  }
775
980
  results.sort((a, b) => Number(b.time - a.time));
776
981
  return results;
777
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
+ }
778
1011
  async function listAttestations(params) {
779
1012
  const limit = params.limit ?? 20;
780
1013
  if (limit <= 0) {
@@ -785,34 +1018,15 @@ async function listAttestations(params) {
785
1018
  }
786
1019
  async function getLatestAttestations(params) {
787
1020
  const provider = params.provider;
788
- const contract = new ethers.Contract(params.easContractAddress, EAS_EVENT_ABI, provider);
789
- const currentBlock = await provider.getBlockNumber();
790
- const fromBlock = params.fromBlock ?? Math.max(0, currentBlock - 5e4);
791
- const events = await contract.queryFilter(contract.filters.Attested(), fromBlock, currentBlock);
792
- const eas = new easSdk.EAS(params.easContractAddress);
793
- eas.connect(provider);
794
- const schemaFilter = params.schemas?.map((schema) => schema.toLowerCase());
795
- const results = [];
796
- for (const event of events) {
797
- if (!("args" in event && Array.isArray(event.args))) {
798
- continue;
799
- }
800
- const args = event.args;
801
- const uid = args?.[2];
802
- const schemaUid = args?.[3];
803
- if (!uid || !schemaUid) {
804
- continue;
805
- }
806
- if (schemaFilter && !schemaFilter.includes(schemaUid.toLowerCase())) {
807
- continue;
808
- }
809
- const attestation = await eas.getAttestation(uid);
810
- if (!attestation || !attestation.uid) {
811
- continue;
812
- }
813
- results.push(parseAttestation(attestation));
814
- }
815
- 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
+ );
816
1030
  return results.slice(0, params.limit ?? 20);
817
1031
  }
818
1032
  function deduplicateReviews(attestations) {
@@ -1074,6 +1288,13 @@ function verifyDidDocumentControllerDid(didDocument, expectedControllerDid) {
1074
1288
  reason: `No matching address found in DID document (expected ${expectedAddress})`
1075
1289
  };
1076
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
+ }
1077
1298
  function buildEip712Domain(name, version, chainId, verifyingContract) {
1078
1299
  return { name, version, chainId, verifyingContract };
1079
1300
  }
@@ -1106,6 +1327,8 @@ function verifyEip712Signature(typedData, signature) {
1106
1327
  throw new OmaTrustError("INVALID_INPUT", "Failed to verify EIP-712 signature", { err });
1107
1328
  }
1108
1329
  }
1330
+
1331
+ // src/reputation/proof/dns-txt-record.ts
1109
1332
  function parseDnsTxtRecord(record) {
1110
1333
  if (!record || typeof record !== "string") {
1111
1334
  throw new OmaTrustError("INVALID_INPUT", "record must be a non-empty string", { record });
@@ -1133,27 +1356,6 @@ function buildDnsTxtRecord(controllerDid) {
1133
1356
  const normalized = normalizeDid(controllerDid);
1134
1357
  return `v=1;controller=${normalized}`;
1135
1358
  }
1136
- async function verifyDnsTxtControllerDid(domain, expectedControllerDid) {
1137
- if (!domain || typeof domain !== "string") {
1138
- throw new OmaTrustError("INVALID_INPUT", "domain must be a non-empty string", { domain });
1139
- }
1140
- const expected = normalizeDid(expectedControllerDid);
1141
- const host = `_omatrust.${domain.toLowerCase().replace(/\.$/, "")}`;
1142
- let records;
1143
- try {
1144
- records = await promises.resolveTxt(host);
1145
- } catch (err) {
1146
- throw new OmaTrustError("NETWORK_ERROR", "Failed to resolve DNS TXT records", { domain, err });
1147
- }
1148
- for (const recordParts of records) {
1149
- const record = recordParts.join("");
1150
- const parsed = parseDnsTxtRecord(record);
1151
- if (parsed.version === "1" && parsed.controller && normalizeDid(parsed.controller) === expected) {
1152
- return { valid: true, record };
1153
- }
1154
- }
1155
- return { valid: false, reason: "No TXT record matched expected controller DID" };
1156
- }
1157
1359
 
1158
1360
  // src/reputation/verify.ts
1159
1361
  function parseChainId(input) {
@@ -1434,6 +1636,9 @@ async function getSchemaDetails(schemaRegistry, schemaUid) {
1434
1636
  revocable: Boolean(details.revocable)
1435
1637
  };
1436
1638
  } catch (err) {
1639
+ if (isEasSchemaNotFoundError(err)) {
1640
+ throw new OmaTrustError("SCHEMA_NOT_FOUND", "Schema was not found", { schemaUid });
1641
+ }
1437
1642
  if (err instanceof OmaTrustError) {
1438
1643
  throw err;
1439
1644
  }
@@ -1617,6 +1822,366 @@ function createEvidencePointerProof(url) {
1617
1822
  issuedAt: Math.floor(Date.now() / 1e3)
1618
1823
  };
1619
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
+ }
1620
2185
 
1621
2186
  // src/app-registry/index.ts
1622
2187
  var app_registry_exports = {};