@oma3/omatrust 0.1.0-alpha.4 → 0.1.0-alpha.6

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.
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { i as identity } from './index-QZDExA4I.cjs';
2
- export { i as reputation } from './index-DP6IIpIh.cjs';
2
+ export { i as reputation } from './index-BsUwj4r5.cjs';
3
3
  export { i as appRegistry } from './index-_Bkhoj8k.cjs';
4
- import './eip712-C4a-JGko.cjs';
4
+ import './eip712-CevLiOcD.cjs';
5
5
 
6
6
  declare class OmaTrustError extends Error {
7
7
  code: string;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { i as identity } from './index-QZDExA4I.js';
2
- export { i as reputation } from './index-BDeQNCi_.js';
2
+ export { i as reputation } from './index-pYFRyitI.js';
3
3
  export { i as appRegistry } from './index-_Bkhoj8k.js';
4
- import './eip712-C4a-JGko.js';
4
+ import './eip712-CevLiOcD.js';
5
5
 
6
6
  declare class OmaTrustError extends Error {
7
7
  code: string;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { keccak256, toUtf8Bytes, isAddress, getAddress, sha256, ZeroAddress, Signature, Contract, formatUnits, verifyTypedData, hexlify, randomBytes, id } from 'ethers';
1
+ import { keccak256, toUtf8Bytes, isAddress, getAddress, sha256, ZeroAddress, Signature, formatUnits, verifyTypedData, hexlify, randomBytes, id, Contract } from 'ethers';
2
2
  import canonicalize from 'canonicalize';
3
3
  import { SchemaEncoder, EAS } from '@ethereum-attestation-service/eas-sdk';
4
4
  import { resolveTxt } from 'dns/promises';
@@ -379,6 +379,7 @@ __export(reputation_exports, {
379
379
  formatSchemaUid: () => formatSchemaUid,
380
380
  formatTransferAmount: () => formatTransferAmount,
381
381
  getAttestation: () => getAttestation,
382
+ getAttestationsByAttester: () => getAttestationsByAttester,
382
383
  getAttestationsForDid: () => getAttestationsForDid,
383
384
  getChainConstants: () => getChainConstants,
384
385
  getExplorerAddressUrl: () => getExplorerAddressUrl,
@@ -394,10 +395,12 @@ __export(reputation_exports, {
394
395
  normalizeSchema: () => normalizeSchema,
395
396
  parseDnsTxtRecord: () => parseDnsTxtRecord,
396
397
  prepareDelegatedAttestation: () => prepareDelegatedAttestation,
398
+ revokeAttestation: () => revokeAttestation,
397
399
  schemaToString: () => schemaToString,
398
400
  splitSignature: () => splitSignature,
399
401
  submitAttestation: () => submitAttestation,
400
402
  submitDelegatedAttestation: () => submitDelegatedAttestation,
403
+ validateAttestationData: () => validateAttestationData,
401
404
  verifyAttestation: () => verifyAttestation,
402
405
  verifyDidDocumentControllerDid: () => verifyDidDocumentControllerDid,
403
406
  verifyDnsTxtControllerDid: () => verifyDnsTxtControllerDid,
@@ -439,6 +442,13 @@ function encodeAttestationData(schema, data) {
439
442
  if (!data || typeof data !== "object") {
440
443
  throw new OmaTrustError("INVALID_INPUT", "data must be an object");
441
444
  }
445
+ const validationErrors = validateAttestationData(schema, data);
446
+ if (validationErrors.length > 0) {
447
+ const summary = validationErrors.map((error) => `Field "${error.schemaFieldName}" (${error.expectedType}) got ${error.providedType}`).join("; ");
448
+ throw new OmaTrustError("INVALID_INPUT", `Attestation data validation failed: ${summary}`, {
449
+ errors: validationErrors
450
+ });
451
+ }
442
452
  const fields = normalizeSchema(schema);
443
453
  const schemaString = schemaToString(fields);
444
454
  const encoder = new SchemaEncoder(schemaString);
@@ -451,6 +461,99 @@ function encodeAttestationData(schema, data) {
451
461
  );
452
462
  return encoded;
453
463
  }
464
+ function getActualType(value) {
465
+ if (value === null) {
466
+ return "null";
467
+ }
468
+ if (value === void 0) {
469
+ return "undefined";
470
+ }
471
+ if (Array.isArray(value)) {
472
+ return "array";
473
+ }
474
+ if (typeof value === "number") {
475
+ return Number.isFinite(value) ? "number" : "non-finite-number";
476
+ }
477
+ return typeof value;
478
+ }
479
+ function isNumericValue(value, allowNegative) {
480
+ if (typeof value === "bigint") {
481
+ return allowNegative || value >= 0n;
482
+ }
483
+ if (typeof value === "number") {
484
+ if (!Number.isFinite(value) || !Number.isInteger(value)) {
485
+ return false;
486
+ }
487
+ return allowNegative || value >= 0;
488
+ }
489
+ if (typeof value === "string") {
490
+ if (value.length === 0) {
491
+ return false;
492
+ }
493
+ const pattern = allowNegative ? /^-?\d+$/ : /^\d+$/;
494
+ return pattern.test(value);
495
+ }
496
+ return false;
497
+ }
498
+ function isHex(value) {
499
+ return typeof value === "string" && /^0x[0-9a-fA-F]*$/.test(value);
500
+ }
501
+ function validateFieldValue(type, value) {
502
+ const normalizedType = type.trim().toLowerCase();
503
+ const bytesNMatch = normalizedType.match(/^bytes([1-9]|[12]\d|3[0-2])$/);
504
+ if (/^uint\d*$/.test(normalizedType)) {
505
+ return isNumericValue(value, false);
506
+ }
507
+ if (/^int\d*$/.test(normalizedType)) {
508
+ return isNumericValue(value, true);
509
+ }
510
+ if (normalizedType === "string") {
511
+ return typeof value === "string";
512
+ }
513
+ if (normalizedType === "string[]") {
514
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
515
+ }
516
+ if (normalizedType === "bool") {
517
+ return typeof value === "boolean";
518
+ }
519
+ if (normalizedType === "address") {
520
+ return typeof value === "string" && isAddress(value);
521
+ }
522
+ if (normalizedType === "bytes") {
523
+ return isHex(value) && (value.length - 2) % 2 === 0;
524
+ }
525
+ if (bytesNMatch) {
526
+ const expectedBytes = Number(bytesNMatch[1]);
527
+ return isHex(value) && value.length === 2 + expectedBytes * 2;
528
+ }
529
+ return true;
530
+ }
531
+ function validateAttestationData(schema, data) {
532
+ if (!data || typeof data !== "object") {
533
+ return [{
534
+ schemaFieldName: "data",
535
+ expectedType: "object",
536
+ providedType: getActualType(data),
537
+ providedValue: data
538
+ }];
539
+ }
540
+ const fields = normalizeSchema(schema);
541
+ const errors = [];
542
+ for (const field of fields) {
543
+ const value = data[field.name];
544
+ const isValid = validateFieldValue(field.type, value);
545
+ if (isValid) {
546
+ continue;
547
+ }
548
+ errors.push({
549
+ schemaFieldName: field.name,
550
+ expectedType: field.type,
551
+ providedType: getActualType(value),
552
+ providedValue: value
553
+ });
554
+ }
555
+ return errors;
556
+ }
454
557
  function decodeAttestationData(schema, encodedData) {
455
558
  if (typeof encodedData !== "string" || !encodedData.startsWith("0x")) {
456
559
  throw new OmaTrustError("INVALID_INPUT", "encodedData must be a hex string");
@@ -471,22 +574,11 @@ function decodeAttestationData(schema, encodedData) {
471
574
  return result;
472
575
  }
473
576
  function extractExpirationTime(data) {
474
- const keys = ["expirationTime", "expiration", "validUntil", "expiresAt", "expires"];
475
- for (const key of keys) {
476
- const value = data[key];
477
- if (value === void 0 || value === null) {
478
- continue;
479
- }
480
- if (typeof value === "bigint") {
481
- return value;
482
- }
483
- if (typeof value === "number") {
484
- return value;
485
- }
486
- if (typeof value === "string" && /^\d+$/.test(value)) {
487
- return BigInt(value);
488
- }
489
- }
577
+ const value = data["expiresAt"];
578
+ if (value === void 0 || value === null) return void 0;
579
+ if (typeof value === "bigint") return value;
580
+ if (typeof value === "number") return value;
581
+ if (typeof value === "string" && /^\d+$/.test(value)) return BigInt(value);
490
582
  return void 0;
491
583
  }
492
584
  var ZERO_UID = "0x0000000000000000000000000000000000000000000000000000000000000000";
@@ -615,6 +707,34 @@ async function submitAttestation(params) {
615
707
  throw new OmaTrustError("NETWORK_ERROR", "Failed to submit attestation", { err });
616
708
  }
617
709
  }
710
+ async function revokeAttestation(params) {
711
+ if (!params || typeof params !== "object") {
712
+ throw new OmaTrustError("INVALID_INPUT", "params must be provided");
713
+ }
714
+ if (!params.signer) {
715
+ throw new OmaTrustError("INVALID_INPUT", "signer is required");
716
+ }
717
+ const eas = new EAS(params.easContractAddress);
718
+ eas.connect(params.signer);
719
+ try {
720
+ const tx = await eas.revoke({
721
+ schema: params.schemaUid,
722
+ data: {
723
+ uid: params.uid,
724
+ value: toBigIntOrDefault(params.value, 0n)
725
+ }
726
+ });
727
+ await tx.wait();
728
+ const txHash = getEasTransactionHash(tx) ?? ZERO_UID;
729
+ const receipt = getEasTransactionReceipt(tx);
730
+ return {
731
+ txHash,
732
+ receipt
733
+ };
734
+ } catch (err) {
735
+ throw new OmaTrustError("NETWORK_ERROR", "Failed to revoke attestation", { err });
736
+ }
737
+ }
618
738
  function buildDelegatedTypedData(params) {
619
739
  return {
620
740
  domain: {
@@ -762,7 +882,14 @@ async function submitDelegatedAttestation(params) {
762
882
  var EAS_EVENT_ABI = [
763
883
  "event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID)"
764
884
  ];
765
- function parseAttestation(attestation, schema) {
885
+ function parseEventTxHash(event) {
886
+ const txHash = event.transactionHash;
887
+ if (typeof txHash !== "string") {
888
+ return void 0;
889
+ }
890
+ return /^0x[0-9a-fA-F]{64}$/.test(txHash) ? txHash : void 0;
891
+ }
892
+ function parseAttestation(attestation, schema, txHash) {
766
893
  const rawData = attestation.data ?? "0x";
767
894
  const decoded = schema ? decodeAttestationData(schema, rawData) : {};
768
895
  const toBigIntSafe = (value) => {
@@ -782,6 +909,7 @@ function parseAttestation(attestation, schema) {
782
909
  schema: attestation.schema,
783
910
  attester: attestation.attester,
784
911
  recipient: attestation.recipient,
912
+ txHash,
785
913
  revocable: Boolean(attestation.revocable),
786
914
  revocationTime: toBigIntSafe(attestation.revocationTime),
787
915
  expirationTime: toBigIntSafe(attestation.expirationTime),
@@ -807,21 +935,18 @@ async function getAttestation(params) {
807
935
  throw new OmaTrustError("NETWORK_ERROR", "Failed to read attestation", { err });
808
936
  }
809
937
  }
810
- async function getAttestationsForDid(params) {
811
- const provider = params.provider;
812
- const contract = new Contract(params.easContractAddress, EAS_EVENT_ABI, provider);
813
- const toBlock = params.toBlock ?? await provider.getBlockNumber();
814
- const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
815
- const filter = contract.filters.Attested(didToAddress(params.did));
938
+ async function queryAttestationEvents(easContractAddress, provider, fromBlock, toBlock, options) {
939
+ const contract = new Contract(easContractAddress, EAS_EVENT_ABI, provider);
940
+ const filter = contract.filters.Attested(options?.recipient ?? null, options?.attester ?? null);
816
941
  let events;
817
942
  try {
818
943
  events = await contract.queryFilter(filter, fromBlock, toBlock);
819
944
  } catch (err) {
820
945
  throw new OmaTrustError("NETWORK_ERROR", "Failed to query attestation events", { err });
821
946
  }
822
- const eas = new EAS(params.easContractAddress);
947
+ const eas = new EAS(easContractAddress);
823
948
  eas.connect(provider);
824
- const schemaFilter = params.schemas?.map((schema) => schema.toLowerCase());
949
+ const schemaFilter = options?.schemas?.map((s) => s.toLowerCase());
825
950
  const results = [];
826
951
  for (const event of events) {
827
952
  if (!("args" in event && Array.isArray(event.args))) {
@@ -840,11 +965,39 @@ async function getAttestationsForDid(params) {
840
965
  if (!attestation || !attestation.uid) {
841
966
  continue;
842
967
  }
843
- results.push(parseAttestation(attestation));
968
+ results.push(parseAttestation(attestation, void 0, parseEventTxHash(event)));
844
969
  }
845
970
  results.sort((a, b) => Number(b.time - a.time));
846
971
  return results;
847
972
  }
973
+ async function getAttestationsForDid(params) {
974
+ const provider = params.provider;
975
+ const toBlock = params.toBlock ?? await provider.getBlockNumber();
976
+ const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
977
+ return queryAttestationEvents(
978
+ params.easContractAddress,
979
+ provider,
980
+ fromBlock,
981
+ toBlock,
982
+ { recipient: didToAddress(params.did), schemas: params.schemas }
983
+ );
984
+ }
985
+ async function getAttestationsByAttester(params) {
986
+ const provider = params.provider;
987
+ const toBlock = params.toBlock ?? await provider.getBlockNumber();
988
+ const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
989
+ if (params.limit !== void 0 && params.limit <= 0) {
990
+ return [];
991
+ }
992
+ const results = await queryAttestationEvents(
993
+ params.easContractAddress,
994
+ provider,
995
+ fromBlock,
996
+ toBlock,
997
+ { attester: params.attester, schemas: params.schemas }
998
+ );
999
+ return params.limit !== void 0 ? results.slice(0, params.limit) : results;
1000
+ }
848
1001
  async function listAttestations(params) {
849
1002
  const limit = params.limit ?? 20;
850
1003
  if (limit <= 0) {
@@ -855,34 +1008,15 @@ async function listAttestations(params) {
855
1008
  }
856
1009
  async function getLatestAttestations(params) {
857
1010
  const provider = params.provider;
858
- const contract = new Contract(params.easContractAddress, EAS_EVENT_ABI, provider);
859
- const currentBlock = await provider.getBlockNumber();
860
- const fromBlock = params.fromBlock ?? Math.max(0, currentBlock - 5e4);
861
- const events = await contract.queryFilter(contract.filters.Attested(), fromBlock, currentBlock);
862
- const eas = new EAS(params.easContractAddress);
863
- eas.connect(provider);
864
- const schemaFilter = params.schemas?.map((schema) => schema.toLowerCase());
865
- const results = [];
866
- for (const event of events) {
867
- if (!("args" in event && Array.isArray(event.args))) {
868
- continue;
869
- }
870
- const args = event.args;
871
- const uid = args?.[2];
872
- const schemaUid = args?.[3];
873
- if (!uid || !schemaUid) {
874
- continue;
875
- }
876
- if (schemaFilter && !schemaFilter.includes(schemaUid.toLowerCase())) {
877
- continue;
878
- }
879
- const attestation = await eas.getAttestation(uid);
880
- if (!attestation || !attestation.uid) {
881
- continue;
882
- }
883
- results.push(parseAttestation(attestation));
884
- }
885
- results.sort((a, b) => Number(b.time - a.time));
1011
+ const toBlock = await provider.getBlockNumber();
1012
+ const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
1013
+ const results = await queryAttestationEvents(
1014
+ params.easContractAddress,
1015
+ provider,
1016
+ fromBlock,
1017
+ toBlock,
1018
+ { schemas: params.schemas }
1019
+ );
886
1020
  return results.slice(0, params.limit ?? 20);
887
1021
  }
888
1022
  function deduplicateReviews(attestations) {