@oma3/omatrust 0.1.0-alpha.5 → 0.1.0-alpha.7

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-ByNU5VpJ.cjs';
2
+ export { i as reputation } from './index-BsUwj4r5.cjs';
3
3
  export { i as appRegistry } from './index-_Bkhoj8k.cjs';
4
- import './eip712-Dx9kvqtn.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-BUWbuvqZ.js';
2
+ export { i as reputation } from './index-pYFRyitI.js';
3
3
  export { i as appRegistry } from './index-_Bkhoj8k.js';
4
- import './eip712-Dx9kvqtn.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: {
@@ -815,21 +935,18 @@ async function getAttestation(params) {
815
935
  throw new OmaTrustError("NETWORK_ERROR", "Failed to read attestation", { err });
816
936
  }
817
937
  }
818
- async function getAttestationsForDid(params) {
819
- const provider = params.provider;
820
- const contract = new Contract(params.easContractAddress, EAS_EVENT_ABI, provider);
821
- const toBlock = params.toBlock ?? await provider.getBlockNumber();
822
- const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
823
- 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);
824
941
  let events;
825
942
  try {
826
943
  events = await contract.queryFilter(filter, fromBlock, toBlock);
827
944
  } catch (err) {
828
945
  throw new OmaTrustError("NETWORK_ERROR", "Failed to query attestation events", { err });
829
946
  }
830
- const eas = new EAS(params.easContractAddress);
947
+ const eas = new EAS(easContractAddress);
831
948
  eas.connect(provider);
832
- const schemaFilter = params.schemas?.map((schema) => schema.toLowerCase());
949
+ const schemaFilter = options?.schemas?.map((s) => s.toLowerCase());
833
950
  const results = [];
834
951
  for (const event of events) {
835
952
  if (!("args" in event && Array.isArray(event.args))) {
@@ -853,6 +970,34 @@ async function getAttestationsForDid(params) {
853
970
  results.sort((a, b) => Number(b.time - a.time));
854
971
  return results;
855
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
+ }
856
1001
  async function listAttestations(params) {
857
1002
  const limit = params.limit ?? 20;
858
1003
  if (limit <= 0) {
@@ -863,34 +1008,15 @@ async function listAttestations(params) {
863
1008
  }
864
1009
  async function getLatestAttestations(params) {
865
1010
  const provider = params.provider;
866
- const contract = new Contract(params.easContractAddress, EAS_EVENT_ABI, provider);
867
- const currentBlock = await provider.getBlockNumber();
868
- const fromBlock = params.fromBlock ?? Math.max(0, currentBlock - 5e4);
869
- const events = await contract.queryFilter(contract.filters.Attested(), fromBlock, currentBlock);
870
- const eas = new EAS(params.easContractAddress);
871
- eas.connect(provider);
872
- const schemaFilter = params.schemas?.map((schema) => schema.toLowerCase());
873
- const results = [];
874
- for (const event of events) {
875
- if (!("args" in event && Array.isArray(event.args))) {
876
- continue;
877
- }
878
- const args = event.args;
879
- const uid = args?.[2];
880
- const schemaUid = args?.[3];
881
- if (!uid || !schemaUid) {
882
- continue;
883
- }
884
- if (schemaFilter && !schemaFilter.includes(schemaUid.toLowerCase())) {
885
- continue;
886
- }
887
- const attestation = await eas.getAttestation(uid);
888
- if (!attestation || !attestation.uid) {
889
- continue;
890
- }
891
- results.push(parseAttestation(attestation, void 0, parseEventTxHash(event)));
892
- }
893
- 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
+ );
894
1020
  return results.slice(0, params.limit ?? 20);
895
1021
  }
896
1022
  function deduplicateReviews(attestations) {