@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.
@@ -57,6 +57,13 @@ function encodeAttestationData(schema, data) {
57
57
  if (!data || typeof data !== "object") {
58
58
  throw new OmaTrustError("INVALID_INPUT", "data must be an object");
59
59
  }
60
+ const validationErrors = validateAttestationData(schema, data);
61
+ if (validationErrors.length > 0) {
62
+ const summary = validationErrors.map((error) => `Field "${error.schemaFieldName}" (${error.expectedType}) got ${error.providedType}`).join("; ");
63
+ throw new OmaTrustError("INVALID_INPUT", `Attestation data validation failed: ${summary}`, {
64
+ errors: validationErrors
65
+ });
66
+ }
60
67
  const fields = normalizeSchema(schema);
61
68
  const schemaString = schemaToString(fields);
62
69
  const encoder = new easSdk.SchemaEncoder(schemaString);
@@ -69,6 +76,99 @@ function encodeAttestationData(schema, data) {
69
76
  );
70
77
  return encoded;
71
78
  }
79
+ function getActualType(value) {
80
+ if (value === null) {
81
+ return "null";
82
+ }
83
+ if (value === void 0) {
84
+ return "undefined";
85
+ }
86
+ if (Array.isArray(value)) {
87
+ return "array";
88
+ }
89
+ if (typeof value === "number") {
90
+ return Number.isFinite(value) ? "number" : "non-finite-number";
91
+ }
92
+ return typeof value;
93
+ }
94
+ function isNumericValue(value, allowNegative) {
95
+ if (typeof value === "bigint") {
96
+ return allowNegative || value >= 0n;
97
+ }
98
+ if (typeof value === "number") {
99
+ if (!Number.isFinite(value) || !Number.isInteger(value)) {
100
+ return false;
101
+ }
102
+ return allowNegative || value >= 0;
103
+ }
104
+ if (typeof value === "string") {
105
+ if (value.length === 0) {
106
+ return false;
107
+ }
108
+ const pattern = allowNegative ? /^-?\d+$/ : /^\d+$/;
109
+ return pattern.test(value);
110
+ }
111
+ return false;
112
+ }
113
+ function isHex(value) {
114
+ return typeof value === "string" && /^0x[0-9a-fA-F]*$/.test(value);
115
+ }
116
+ function validateFieldValue(type, value) {
117
+ const normalizedType = type.trim().toLowerCase();
118
+ const bytesNMatch = normalizedType.match(/^bytes([1-9]|[12]\d|3[0-2])$/);
119
+ if (/^uint\d*$/.test(normalizedType)) {
120
+ return isNumericValue(value, false);
121
+ }
122
+ if (/^int\d*$/.test(normalizedType)) {
123
+ return isNumericValue(value, true);
124
+ }
125
+ if (normalizedType === "string") {
126
+ return typeof value === "string";
127
+ }
128
+ if (normalizedType === "string[]") {
129
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
130
+ }
131
+ if (normalizedType === "bool") {
132
+ return typeof value === "boolean";
133
+ }
134
+ if (normalizedType === "address") {
135
+ return typeof value === "string" && ethers.isAddress(value);
136
+ }
137
+ if (normalizedType === "bytes") {
138
+ return isHex(value) && (value.length - 2) % 2 === 0;
139
+ }
140
+ if (bytesNMatch) {
141
+ const expectedBytes = Number(bytesNMatch[1]);
142
+ return isHex(value) && value.length === 2 + expectedBytes * 2;
143
+ }
144
+ return true;
145
+ }
146
+ function validateAttestationData(schema, data) {
147
+ if (!data || typeof data !== "object") {
148
+ return [{
149
+ schemaFieldName: "data",
150
+ expectedType: "object",
151
+ providedType: getActualType(data),
152
+ providedValue: data
153
+ }];
154
+ }
155
+ const fields = normalizeSchema(schema);
156
+ const errors = [];
157
+ for (const field of fields) {
158
+ const value = data[field.name];
159
+ const isValid = validateFieldValue(field.type, value);
160
+ if (isValid) {
161
+ continue;
162
+ }
163
+ errors.push({
164
+ schemaFieldName: field.name,
165
+ expectedType: field.type,
166
+ providedType: getActualType(value),
167
+ providedValue: value
168
+ });
169
+ }
170
+ return errors;
171
+ }
72
172
  function decodeAttestationData(schema, encodedData) {
73
173
  if (typeof encodedData !== "string" || !encodedData.startsWith("0x")) {
74
174
  throw new OmaTrustError("INVALID_INPUT", "encodedData must be a hex string");
@@ -89,22 +189,11 @@ function decodeAttestationData(schema, encodedData) {
89
189
  return result;
90
190
  }
91
191
  function extractExpirationTime(data) {
92
- const keys = ["expirationTime", "expiration", "validUntil", "expiresAt", "expires"];
93
- for (const key of keys) {
94
- const value = data[key];
95
- if (value === void 0 || value === null) {
96
- continue;
97
- }
98
- if (typeof value === "bigint") {
99
- return value;
100
- }
101
- if (typeof value === "number") {
102
- return value;
103
- }
104
- if (typeof value === "string" && /^\d+$/.test(value)) {
105
- return BigInt(value);
106
- }
107
- }
192
+ const value = data["expiresAt"];
193
+ if (value === void 0 || value === null) return void 0;
194
+ if (typeof value === "bigint") return value;
195
+ if (typeof value === "number") return value;
196
+ if (typeof value === "string" && /^\d+$/.test(value)) return BigInt(value);
108
197
  return void 0;
109
198
  }
110
199
 
@@ -417,6 +506,34 @@ async function submitAttestation(params) {
417
506
  throw new OmaTrustError("NETWORK_ERROR", "Failed to submit attestation", { err });
418
507
  }
419
508
  }
509
+ async function revokeAttestation(params) {
510
+ if (!params || typeof params !== "object") {
511
+ throw new OmaTrustError("INVALID_INPUT", "params must be provided");
512
+ }
513
+ if (!params.signer) {
514
+ throw new OmaTrustError("INVALID_INPUT", "signer is required");
515
+ }
516
+ const eas = new easSdk.EAS(params.easContractAddress);
517
+ eas.connect(params.signer);
518
+ try {
519
+ const tx = await eas.revoke({
520
+ schema: params.schemaUid,
521
+ data: {
522
+ uid: params.uid,
523
+ value: toBigIntOrDefault(params.value, 0n)
524
+ }
525
+ });
526
+ await tx.wait();
527
+ const txHash = getEasTransactionHash(tx) ?? ZERO_UID;
528
+ const receipt = getEasTransactionReceipt(tx);
529
+ return {
530
+ txHash,
531
+ receipt
532
+ };
533
+ } catch (err) {
534
+ throw new OmaTrustError("NETWORK_ERROR", "Failed to revoke attestation", { err });
535
+ }
536
+ }
420
537
  function buildDelegatedTypedData(params) {
421
538
  return {
422
539
  domain: {
@@ -617,21 +734,18 @@ async function getAttestation(params) {
617
734
  throw new OmaTrustError("NETWORK_ERROR", "Failed to read attestation", { err });
618
735
  }
619
736
  }
620
- async function getAttestationsForDid(params) {
621
- const provider = params.provider;
622
- const contract = new ethers.Contract(params.easContractAddress, EAS_EVENT_ABI, provider);
623
- const toBlock = params.toBlock ?? await provider.getBlockNumber();
624
- const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
625
- const filter = contract.filters.Attested(didToAddress(params.did));
737
+ async function queryAttestationEvents(easContractAddress, provider, fromBlock, toBlock, options) {
738
+ const contract = new ethers.Contract(easContractAddress, EAS_EVENT_ABI, provider);
739
+ const filter = contract.filters.Attested(options?.recipient ?? null, options?.attester ?? null);
626
740
  let events;
627
741
  try {
628
742
  events = await contract.queryFilter(filter, fromBlock, toBlock);
629
743
  } catch (err) {
630
744
  throw new OmaTrustError("NETWORK_ERROR", "Failed to query attestation events", { err });
631
745
  }
632
- const eas = new easSdk.EAS(params.easContractAddress);
746
+ const eas = new easSdk.EAS(easContractAddress);
633
747
  eas.connect(provider);
634
- const schemaFilter = params.schemas?.map((schema) => schema.toLowerCase());
748
+ const schemaFilter = options?.schemas?.map((s) => s.toLowerCase());
635
749
  const results = [];
636
750
  for (const event of events) {
637
751
  if (!("args" in event && Array.isArray(event.args))) {
@@ -655,6 +769,34 @@ async function getAttestationsForDid(params) {
655
769
  results.sort((a, b) => Number(b.time - a.time));
656
770
  return results;
657
771
  }
772
+ async function getAttestationsForDid(params) {
773
+ const provider = params.provider;
774
+ const toBlock = params.toBlock ?? await provider.getBlockNumber();
775
+ const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
776
+ return queryAttestationEvents(
777
+ params.easContractAddress,
778
+ provider,
779
+ fromBlock,
780
+ toBlock,
781
+ { recipient: didToAddress(params.did), schemas: params.schemas }
782
+ );
783
+ }
784
+ async function getAttestationsByAttester(params) {
785
+ const provider = params.provider;
786
+ const toBlock = params.toBlock ?? await provider.getBlockNumber();
787
+ const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
788
+ if (params.limit !== void 0 && params.limit <= 0) {
789
+ return [];
790
+ }
791
+ const results = await queryAttestationEvents(
792
+ params.easContractAddress,
793
+ provider,
794
+ fromBlock,
795
+ toBlock,
796
+ { attester: params.attester, schemas: params.schemas }
797
+ );
798
+ return params.limit !== void 0 ? results.slice(0, params.limit) : results;
799
+ }
658
800
  async function listAttestations(params) {
659
801
  const limit = params.limit ?? 20;
660
802
  if (limit <= 0) {
@@ -665,34 +807,15 @@ async function listAttestations(params) {
665
807
  }
666
808
  async function getLatestAttestations(params) {
667
809
  const provider = params.provider;
668
- const contract = new ethers.Contract(params.easContractAddress, EAS_EVENT_ABI, provider);
669
- const currentBlock = await provider.getBlockNumber();
670
- const fromBlock = params.fromBlock ?? Math.max(0, currentBlock - 5e4);
671
- const events = await contract.queryFilter(contract.filters.Attested(), fromBlock, currentBlock);
672
- const eas = new easSdk.EAS(params.easContractAddress);
673
- eas.connect(provider);
674
- const schemaFilter = params.schemas?.map((schema) => schema.toLowerCase());
675
- const results = [];
676
- for (const event of events) {
677
- if (!("args" in event && Array.isArray(event.args))) {
678
- continue;
679
- }
680
- const args = event.args;
681
- const uid = args?.[2];
682
- const schemaUid = args?.[3];
683
- if (!uid || !schemaUid) {
684
- continue;
685
- }
686
- if (schemaFilter && !schemaFilter.includes(schemaUid.toLowerCase())) {
687
- continue;
688
- }
689
- const attestation = await eas.getAttestation(uid);
690
- if (!attestation || !attestation.uid) {
691
- continue;
692
- }
693
- results.push(parseAttestation(attestation, void 0, parseEventTxHash(event)));
694
- }
695
- results.sort((a, b) => Number(b.time - a.time));
810
+ const toBlock = await provider.getBlockNumber();
811
+ const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
812
+ const results = await queryAttestationEvents(
813
+ params.easContractAddress,
814
+ provider,
815
+ fromBlock,
816
+ toBlock,
817
+ { schemas: params.schemas }
818
+ );
696
819
  return results.slice(0, params.limit ?? 20);
697
820
  }
698
821
  function deduplicateReviews(attestations) {
@@ -1519,6 +1642,7 @@ exports.fetchDidDocument = fetchDidDocument;
1519
1642
  exports.formatSchemaUid = formatSchemaUid;
1520
1643
  exports.formatTransferAmount = formatTransferAmount;
1521
1644
  exports.getAttestation = getAttestation;
1645
+ exports.getAttestationsByAttester = getAttestationsByAttester;
1522
1646
  exports.getAttestationsForDid = getAttestationsForDid;
1523
1647
  exports.getChainConstants = getChainConstants;
1524
1648
  exports.getExplorerAddressUrl = getExplorerAddressUrl;
@@ -1534,10 +1658,12 @@ exports.listAttestations = listAttestations;
1534
1658
  exports.normalizeSchema = normalizeSchema;
1535
1659
  exports.parseDnsTxtRecord = parseDnsTxtRecord;
1536
1660
  exports.prepareDelegatedAttestation = prepareDelegatedAttestation;
1661
+ exports.revokeAttestation = revokeAttestation;
1537
1662
  exports.schemaToString = schemaToString;
1538
1663
  exports.splitSignature = splitSignature;
1539
1664
  exports.submitAttestation = submitAttestation;
1540
1665
  exports.submitDelegatedAttestation = submitDelegatedAttestation;
1666
+ exports.validateAttestationData = validateAttestationData;
1541
1667
  exports.verifyAttestation = verifyAttestation;
1542
1668
  exports.verifyDidDocumentControllerDid = verifyDidDocumentControllerDid;
1543
1669
  exports.verifyDnsTxtControllerDid = verifyDnsTxtControllerDid;