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

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 (48) hide show
  1. package/README.md +3 -0
  2. package/dist/app-registry/index.cjs +53 -0
  3. package/dist/app-registry/index.cjs.map +1 -1
  4. package/dist/app-registry/index.js +53 -0
  5. package/dist/app-registry/index.js.map +1 -1
  6. package/dist/identity/index.cjs +1028 -6
  7. package/dist/identity/index.cjs.map +1 -1
  8. package/dist/identity/index.d.cts +2 -1
  9. package/dist/identity/index.d.ts +2 -1
  10. package/dist/identity/index.js +984 -7
  11. package/dist/identity/index.js.map +1 -1
  12. package/dist/index-B5OC9_8B.d.cts +480 -0
  13. package/dist/index-Bu-xxcv9.d.ts +407 -0
  14. package/dist/index-C6WNgPRx.d.ts +480 -0
  15. package/dist/index-C7odEbp6.d.cts +407 -0
  16. package/dist/index.cjs +2498 -373
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +4 -3
  19. package/dist/index.d.ts +4 -3
  20. package/dist/index.js +2342 -236
  21. package/dist/index.js.map +1 -1
  22. package/dist/reputation/index.browser.cjs +949 -67
  23. package/dist/reputation/index.browser.cjs.map +1 -1
  24. package/dist/reputation/index.browser.d.cts +2 -2
  25. package/dist/reputation/index.browser.d.ts +2 -2
  26. package/dist/reputation/index.browser.js +947 -67
  27. package/dist/reputation/index.browser.js.map +1 -1
  28. package/dist/reputation/index.cjs +1745 -232
  29. package/dist/reputation/index.cjs.map +1 -1
  30. package/dist/reputation/index.d.cts +3 -2
  31. package/dist/reputation/index.d.ts +3 -2
  32. package/dist/reputation/index.js +1727 -232
  33. package/dist/reputation/index.js.map +1 -1
  34. package/dist/{subject-ownership-CXvzEjpH.d.cts → subject-ownership-B7cFlm8c.d.cts} +256 -26
  35. package/dist/{subject-ownership-CXvzEjpH.d.ts → subject-ownership-B7cFlm8c.d.ts} +256 -26
  36. package/dist/types-Dn0OwaNj.d.cts +307 -0
  37. package/dist/types-Dn0OwaNj.d.ts +307 -0
  38. package/dist/widgets/index.cjs +70 -27
  39. package/dist/widgets/index.cjs.map +1 -1
  40. package/dist/widgets/index.d.cts +45 -18
  41. package/dist/widgets/index.d.ts +45 -18
  42. package/dist/widgets/index.js +67 -26
  43. package/dist/widgets/index.js.map +1 -1
  44. package/package.json +5 -2
  45. package/dist/index-B9KW02US.d.cts +0 -119
  46. package/dist/index-DXrwBex9.d.ts +0 -119
  47. package/dist/index-QZDExA4I.d.cts +0 -90
  48. package/dist/index-QZDExA4I.d.ts +0 -90
@@ -1,5 +1,6 @@
1
1
  import { SchemaEncoder, EAS } from '@ethereum-attestation-service/eas-sdk';
2
- import { ZeroAddress, Signature, toUtf8Bytes, sha256, keccak256, formatUnits, getAddress, isAddress, verifyTypedData, hexlify, randomBytes, Contract, Interface } from 'ethers';
2
+ import { ZeroAddress, Signature, toUtf8Bytes, sha256, keccak256, formatUnits, getAddress, isAddress, verifyTypedData, Interface, Contract, hexlify, randomBytes } from 'ethers';
3
+ import { decodeProtectedHeader, importJWK, compactVerify, base64url } from 'jose';
3
4
  import canonicalize from 'canonicalize';
4
5
  import { resolveTxt } from 'dns/promises';
5
6
 
@@ -198,6 +199,11 @@ function assertString(value, name, code = "INVALID_INPUT") {
198
199
  throw new OmaTrustError(code, `${name} must be a non-empty string`, { value });
199
200
  }
200
201
  }
202
+ function assertObject(value, name, code = "INVALID_INPUT") {
203
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
204
+ throw new OmaTrustError(code, `${name} must be an object`, { value });
205
+ }
206
+ }
201
207
 
202
208
  // src/identity/caip.ts
203
209
  var CAIP_10_REGEX = /^(?<namespace>[a-z0-9-]+):(?<reference>[a-zA-Z0-9-]+):(?<address>.+)$/;
@@ -216,6 +222,145 @@ function parseCaip10(input) {
216
222
  }
217
223
  return { namespace, reference, address };
218
224
  }
225
+ var VALID_KTY = /* @__PURE__ */ new Set(["EC", "OKP", "RSA"]);
226
+ var PRIVATE_KEY_FIELDS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
227
+ var REQUIRED_PUBLIC_FIELDS = {
228
+ EC: ["crv", "x", "y"],
229
+ OKP: ["crv", "x"],
230
+ RSA: ["n", "e"]
231
+ };
232
+ function validatePublicJwk(jwk) {
233
+ if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
234
+ return { valid: false, error: "JWK must be a non-null object" };
235
+ }
236
+ const obj = jwk;
237
+ const kty = obj.kty;
238
+ if (typeof kty !== "string" || !VALID_KTY.has(kty)) {
239
+ return {
240
+ valid: false,
241
+ error: `Invalid or missing kty (must be one of: ${[...VALID_KTY].join(", ")})`
242
+ };
243
+ }
244
+ for (const field of PRIVATE_KEY_FIELDS) {
245
+ if (field in obj) {
246
+ return {
247
+ valid: false,
248
+ error: `JWK contains private key field "${field}" \u2014 only public keys are allowed`
249
+ };
250
+ }
251
+ }
252
+ const required = REQUIRED_PUBLIC_FIELDS[kty];
253
+ if (required) {
254
+ for (const field of required) {
255
+ if (!(field in obj) || obj[field] === void 0 || obj[field] === null || obj[field] === "") {
256
+ return {
257
+ valid: false,
258
+ error: `Missing required public key field "${field}" for kty="${kty}"`
259
+ };
260
+ }
261
+ }
262
+ }
263
+ return { valid: true };
264
+ }
265
+ function canonicalizeJwkJson(jwk) {
266
+ const sorted = Object.keys(jwk).sort();
267
+ const obj = {};
268
+ for (const key of sorted) {
269
+ obj[key] = jwk[key];
270
+ }
271
+ return JSON.stringify(obj);
272
+ }
273
+ function jwkToDidJwk(jwk) {
274
+ assertObject(jwk, "jwk", "INVALID_JWK");
275
+ const validation = validatePublicJwk(jwk);
276
+ if (!validation.valid) {
277
+ throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
278
+ }
279
+ const canonical = canonicalizeJwkJson(jwk);
280
+ const encoded = base64url.encode(new TextEncoder().encode(canonical));
281
+ return `did:jwk:${encoded}`;
282
+ }
283
+ function didJwkToJwk(didJwk) {
284
+ if (typeof didJwk !== "string" || !didJwk.startsWith("did:jwk:")) {
285
+ throw new OmaTrustError("INVALID_DID", "Expected a did:jwk DID", { input: didJwk });
286
+ }
287
+ const parts = didJwk.split(":");
288
+ if (parts.length !== 3) {
289
+ throw new OmaTrustError("INVALID_DID", "did:jwk must have exactly 3 colon-separated parts", {
290
+ input: didJwk
291
+ });
292
+ }
293
+ const encoded = parts[2];
294
+ if (!encoded || encoded.length === 0) {
295
+ throw new OmaTrustError("INVALID_DID", "Missing base64url-encoded JWK identifier", {
296
+ input: didJwk
297
+ });
298
+ }
299
+ let decoded;
300
+ try {
301
+ const bytes = base64url.decode(encoded);
302
+ decoded = new TextDecoder().decode(bytes);
303
+ } catch {
304
+ throw new OmaTrustError("INVALID_DID", "Failed to base64url-decode did:jwk identifier", {
305
+ input: didJwk
306
+ });
307
+ }
308
+ let jwk;
309
+ try {
310
+ jwk = JSON.parse(decoded);
311
+ } catch {
312
+ throw new OmaTrustError("INVALID_DID", "Decoded did:jwk identifier is not valid JSON", {
313
+ input: didJwk
314
+ });
315
+ }
316
+ if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
317
+ throw new OmaTrustError("INVALID_DID", "Decoded did:jwk must be a JSON object", {
318
+ input: didJwk
319
+ });
320
+ }
321
+ const validation = validatePublicJwk(jwk);
322
+ if (!validation.valid) {
323
+ throw new OmaTrustError("INVALID_DID", validation.error ?? "Invalid public JWK in did:jwk", {
324
+ input: didJwk
325
+ });
326
+ }
327
+ return jwk;
328
+ }
329
+ function extractPublicKeyFields(jwk) {
330
+ const result = {};
331
+ const metadataFields = /* @__PURE__ */ new Set(["kid", "use", "key_ops", "alg", "ext"]);
332
+ for (const [key, value] of Object.entries(jwk)) {
333
+ if (PRIVATE_KEY_FIELDS.has(key)) continue;
334
+ if (metadataFields.has(key)) continue;
335
+ result[key] = value;
336
+ }
337
+ return result;
338
+ }
339
+ function publicJwkEquals(a, b) {
340
+ assertObject(a, "a", "INVALID_JWK");
341
+ assertObject(b, "b", "INVALID_JWK");
342
+ const aObj = a;
343
+ const bObj = b;
344
+ for (const field of PRIVATE_KEY_FIELDS) {
345
+ if (field in aObj) {
346
+ throw new OmaTrustError(
347
+ "INVALID_JWK",
348
+ `First JWK contains private key field "${field}"`,
349
+ { field }
350
+ );
351
+ }
352
+ if (field in bObj) {
353
+ throw new OmaTrustError(
354
+ "INVALID_JWK",
355
+ `Second JWK contains private key field "${field}"`,
356
+ { field }
357
+ );
358
+ }
359
+ }
360
+ const aPublic = extractPublicKeyFields(aObj);
361
+ const bPublic = extractPublicKeyFields(bObj);
362
+ return canonicalizeJwkJson(aPublic) === canonicalizeJwkJson(bPublic);
363
+ }
219
364
 
220
365
  // src/identity/did.ts
221
366
  var DID_REGEX = /^did:[a-z0-9]+:.+$/i;
@@ -287,7 +432,7 @@ function normalizeDidKey(input) {
287
432
  }
288
433
  function normalizeDid(input) {
289
434
  assertString(input, "input", "INVALID_DID");
290
- const trimmed = input.trim();
435
+ const trimmed = input.trim().split("#")[0];
291
436
  if (!trimmed.startsWith("did:")) {
292
437
  return normalizeDidWeb(trimmed);
293
438
  }
@@ -304,6 +449,8 @@ function normalizeDid(input) {
304
449
  return normalizeDidHandle(trimmed);
305
450
  case "key":
306
451
  return normalizeDidKey(trimmed);
452
+ case "jwk":
453
+ return normalizeDidJwk(trimmed);
307
454
  default:
308
455
  return trimmed;
309
456
  }
@@ -393,6 +540,77 @@ function extractAddressFromDid(identifier) {
393
540
  }
394
541
  throw new OmaTrustError("INVALID_DID", "Unsupported identifier format", { identifier });
395
542
  }
543
+ var BASE64URL_REGEX = /^[A-Za-z0-9_-]+$/;
544
+ var VALID_JWK_KTY = /* @__PURE__ */ new Set(["EC", "OKP", "RSA"]);
545
+ function validateDidJwk(did) {
546
+ const parts = did.split(":");
547
+ if (parts.length !== 3) {
548
+ return {
549
+ valid: false,
550
+ method: "jwk",
551
+ error: `did:jwk must have exactly 3 colon-separated parts, got ${parts.length}`
552
+ };
553
+ }
554
+ const [, , encoded] = parts;
555
+ if (!encoded || encoded.length === 0) {
556
+ return { valid: false, method: "jwk", error: "Missing base64url-encoded JWK identifier" };
557
+ }
558
+ if (!BASE64URL_REGEX.test(encoded)) {
559
+ return {
560
+ valid: false,
561
+ method: "jwk",
562
+ error: "Identifier contains invalid base64url characters"
563
+ };
564
+ }
565
+ let decoded;
566
+ try {
567
+ const bytes = base64url.decode(encoded);
568
+ decoded = new TextDecoder().decode(bytes);
569
+ } catch {
570
+ return { valid: false, method: "jwk", error: "Failed to base64url-decode identifier" };
571
+ }
572
+ let jwk;
573
+ try {
574
+ jwk = JSON.parse(decoded);
575
+ } catch {
576
+ return { valid: false, method: "jwk", error: "Decoded identifier is not valid JSON" };
577
+ }
578
+ if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
579
+ return { valid: false, method: "jwk", error: "Decoded JWK must be a JSON object" };
580
+ }
581
+ const kty = jwk.kty;
582
+ if (typeof kty !== "string" || !VALID_JWK_KTY.has(kty)) {
583
+ return {
584
+ valid: false,
585
+ method: "jwk",
586
+ error: `Invalid or missing kty field (must be one of: EC, OKP, RSA)`
587
+ };
588
+ }
589
+ if ("d" in jwk) {
590
+ return {
591
+ valid: false,
592
+ method: "jwk",
593
+ error: "DID must reference a public key \u2014 private key component (d) is not allowed"
594
+ };
595
+ }
596
+ const jwkValidation = validatePublicJwk(jwk);
597
+ if (!jwkValidation.valid) {
598
+ return { valid: false, method: "jwk", error: jwkValidation.error };
599
+ }
600
+ return { valid: true, method: "jwk" };
601
+ }
602
+ function normalizeDidJwk(input) {
603
+ assertString(input, "input", "INVALID_DID");
604
+ const trimmed = input.trim();
605
+ if (!trimmed.startsWith("did:jwk:")) {
606
+ throw new OmaTrustError("INVALID_DID", "Expected did:jwk DID", { input });
607
+ }
608
+ const result = validateDidJwk(trimmed);
609
+ if (!result.valid) {
610
+ throw new OmaTrustError("INVALID_DID", result.error ?? "Invalid did:jwk", { input });
611
+ }
612
+ return trimmed;
613
+ }
396
614
 
397
615
  // src/reputation/internal.ts
398
616
  var ZERO_UID = "0x0000000000000000000000000000000000000000000000000000000000000000";
@@ -679,19 +897,32 @@ async function submitDelegatedAttestation(params) {
679
897
  payload = {};
680
898
  }
681
899
  if (!response.ok) {
682
- throw new OmaTrustError("NETWORK_ERROR", "Relay submission failed", {
683
- status: response.status,
900
+ const relayError = {
901
+ httpStatus: response.status,
902
+ code: payload.code,
903
+ error: payload.error ?? payload.message,
684
904
  payload
685
- });
905
+ };
906
+ throw new OmaTrustError("RELAY_ERROR", `Relay submission failed (HTTP ${response.status})`, relayError);
686
907
  }
687
908
  const uid = payload.uid ?? ZERO_UID;
688
909
  const txHash = payload.txHash;
689
- const status = payload.status ?? "submitted";
690
- return {
691
- uid,
692
- txHash,
693
- status
694
- };
910
+ const hasConfirmationSignals = payload.status === "confirmed" || payload.success === true || typeof payload.blockNumber === "number";
911
+ const status = hasConfirmationSignals ? "confirmed" : "submitted";
912
+ const relay = {};
913
+ if (typeof payload.blockNumber === "number") relay.blockNumber = payload.blockNumber;
914
+ if (typeof payload.chain === "string") relay.chain = payload.chain;
915
+ if (typeof payload.success === "boolean") relay.success = payload.success;
916
+ for (const key of Object.keys(payload)) {
917
+ if (!["uid", "txHash", "status", "blockNumber", "chain", "success"].includes(key)) {
918
+ relay[key] = payload[key];
919
+ }
920
+ }
921
+ const result = { uid, txHash, status };
922
+ if (Object.keys(relay).length > 0) {
923
+ result.relay = relay;
924
+ }
925
+ return result;
695
926
  }
696
927
  var EAS_EVENT_ABI = [
697
928
  "event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID)"
@@ -793,7 +1024,7 @@ async function getAttestationsForDid(params) {
793
1024
  provider,
794
1025
  fromBlock,
795
1026
  toBlock,
796
- { recipient: didToAddress(params.did), schemas: params.schemas }
1027
+ { recipient: didToAddress(params.subjectDid), schemas: params.schemas }
797
1028
  );
798
1029
  }
799
1030
  async function getAttestationsByAttester(params) {
@@ -1034,6 +1265,8 @@ function getExplorerTxUrl(chainId, txHash) {
1034
1265
  function getExplorerAddressUrl(chainId, address) {
1035
1266
  return `${getConfig(chainId).explorer}/address/${address}`;
1036
1267
  }
1268
+
1269
+ // src/shared/did-document.ts
1037
1270
  async function fetchDidDocument(domain) {
1038
1271
  const normalized = domain.toLowerCase().replace(/\.$/, "");
1039
1272
  const url = `https://${normalized}/.well-known/did.json`;
@@ -1044,15 +1277,16 @@ async function fetchDidDocument(domain) {
1044
1277
  throw new OmaTrustError("NETWORK_ERROR", "Failed to fetch DID document", { domain, err });
1045
1278
  }
1046
1279
  if (!response.ok) {
1047
- throw new OmaTrustError("NETWORK_ERROR", "DID document fetch failed", {
1280
+ throw new OmaTrustError("NETWORK_ERROR", `DID document fetch failed: ${response.status}`, {
1048
1281
  domain,
1049
1282
  status: response.status
1050
1283
  });
1051
1284
  }
1052
- const body = await response.json();
1053
- return body;
1285
+ return await response.json();
1054
1286
  }
1055
- function extractAddressesFromDidDocument(didDocument) {
1287
+
1288
+ // src/reputation/proof/did-json.ts
1289
+ function extractEvmAddressesFromDidDocument(didDocument) {
1056
1290
  const methods = didDocument.verificationMethod;
1057
1291
  if (!Array.isArray(methods)) {
1058
1292
  return [];
@@ -1076,14 +1310,52 @@ function extractAddressesFromDidDocument(didDocument) {
1076
1310
  }
1077
1311
  return [...addresses];
1078
1312
  }
1313
+ function extractJwksFromDidDocument(didDocument) {
1314
+ const methods = didDocument.verificationMethod;
1315
+ if (!Array.isArray(methods)) {
1316
+ return [];
1317
+ }
1318
+ const jwks = [];
1319
+ for (const method of methods) {
1320
+ const publicKeyJwk = method.publicKeyJwk;
1321
+ if (publicKeyJwk && typeof publicKeyJwk === "object" && !Array.isArray(publicKeyJwk)) {
1322
+ jwks.push(publicKeyJwk);
1323
+ }
1324
+ }
1325
+ return jwks;
1326
+ }
1079
1327
  function verifyDidDocumentControllerDid(didDocument, expectedControllerDid) {
1328
+ const method = extractDidMethod(expectedControllerDid);
1329
+ if (method === "jwk") {
1330
+ try {
1331
+ const expectedJwk = didJwkToJwk(expectedControllerDid);
1332
+ const documentJwks = extractJwksFromDidDocument(didDocument);
1333
+ for (const docJwk of documentJwks) {
1334
+ try {
1335
+ if (publicJwkEquals(docJwk, expectedJwk)) {
1336
+ return { valid: true };
1337
+ }
1338
+ } catch {
1339
+ }
1340
+ }
1341
+ return {
1342
+ valid: false,
1343
+ reason: "No matching publicKeyJwk found in DID document verification methods"
1344
+ };
1345
+ } catch {
1346
+ return {
1347
+ valid: false,
1348
+ reason: "Failed to decode did:jwk controller DID"
1349
+ };
1350
+ }
1351
+ }
1080
1352
  let expectedAddress;
1081
1353
  try {
1082
1354
  expectedAddress = getAddress(extractAddressFromDid(expectedControllerDid));
1083
1355
  } catch {
1084
- return { valid: false, reason: "Expected controller DID does not resolve to an EVM address" };
1356
+ return { valid: false, reason: "Controller DID does not resolve to an EVM address and is not did:jwk" };
1085
1357
  }
1086
- const addresses = extractAddressesFromDidDocument(didDocument);
1358
+ const addresses = extractEvmAddressesFromDidDocument(didDocument);
1087
1359
  if (addresses.some((address) => address.toLowerCase() === expectedAddress.toLowerCase())) {
1088
1360
  return { valid: true };
1089
1361
  }
@@ -1139,21 +1411,23 @@ function parseDnsTxtRecord(record) {
1139
1411
  }
1140
1412
  const entries = record.split(/[;\s]+/).map((entry) => entry.trim()).filter(Boolean);
1141
1413
  const parsed = {};
1414
+ const controllers = [];
1142
1415
  for (const entry of entries) {
1143
- const [key, ...valueParts] = entry.split("=");
1144
- if (!key) {
1145
- continue;
1146
- }
1147
- const value = valueParts.join("=");
1148
- if (!value) {
1149
- continue;
1416
+ const eqIndex = entry.indexOf("=");
1417
+ if (eqIndex === -1) continue;
1418
+ const key = entry.slice(0, eqIndex).trim();
1419
+ const value = entry.slice(eqIndex + 1).trim();
1420
+ if (!key || !value) continue;
1421
+ if (key === "controller") {
1422
+ controllers.push(value);
1423
+ } else {
1424
+ parsed[key] = value;
1150
1425
  }
1151
- parsed[key.trim()] = value.trim();
1152
1426
  }
1153
1427
  return {
1154
1428
  version: parsed.v,
1155
- controller: parsed.controller,
1156
- ...parsed
1429
+ controller: controllers[0],
1430
+ controllers
1157
1431
  };
1158
1432
  }
1159
1433
  function buildDnsTxtRecord(controllerDid) {
@@ -1161,107 +1435,556 @@ function buildDnsTxtRecord(controllerDid) {
1161
1435
  return `v=1;controller=${normalized}`;
1162
1436
  }
1163
1437
 
1164
- // src/reputation/verify.ts
1165
- function parseChainId(input) {
1166
- if (typeof input === "number") {
1167
- return input;
1168
- }
1169
- if (typeof input === "string") {
1170
- if (input.includes(":")) {
1171
- const [, chainId] = input.split(":");
1172
- return Number(chainId);
1438
+ // src/identity/did-url.ts
1439
+ var DID_URL_REGEX = /^did:[a-z0-9]+:.+$/i;
1440
+ function parseDidUrl(input) {
1441
+ assertString(input, "input", "INVALID_DID_URL");
1442
+ const trimmed = input.trim();
1443
+ const hashIndex = trimmed.indexOf("#");
1444
+ let did;
1445
+ let fragment;
1446
+ if (hashIndex === -1) {
1447
+ did = trimmed;
1448
+ fragment = null;
1449
+ } else {
1450
+ did = trimmed.slice(0, hashIndex);
1451
+ const rawFragment = trimmed.slice(hashIndex + 1);
1452
+ if (rawFragment.length === 0) {
1453
+ throw new OmaTrustError(
1454
+ "INVALID_DID_URL",
1455
+ "DID URL has empty fragment (trailing '#' with no identifier)",
1456
+ { input }
1457
+ );
1173
1458
  }
1174
- return Number(input);
1459
+ fragment = rawFragment;
1175
1460
  }
1176
- return NaN;
1461
+ if (!DID_URL_REGEX.test(did)) {
1462
+ throw new OmaTrustError(
1463
+ "INVALID_DID_URL",
1464
+ "Invalid DID URL: base DID portion is malformed",
1465
+ { input, did }
1466
+ );
1467
+ }
1468
+ return {
1469
+ didUrl: trimmed,
1470
+ did,
1471
+ fragment
1472
+ };
1177
1473
  }
1178
- function parseProofs(attestation) {
1179
- const rawProofs = attestation.data.proofs;
1180
- if (!Array.isArray(rawProofs)) {
1181
- return [];
1474
+
1475
+ // src/identity/resolve-key.ts
1476
+ function findVerificationMethod(didDocument, didUrl, fragment) {
1477
+ const methods = didDocument.verificationMethod;
1478
+ if (!Array.isArray(methods)) {
1479
+ return null;
1182
1480
  }
1183
- return rawProofs.map((entry) => {
1184
- if (typeof entry === "string") {
1185
- try {
1186
- return JSON.parse(entry);
1187
- } catch {
1188
- return null;
1189
- }
1481
+ for (const method of methods) {
1482
+ if (!method || typeof method !== "object") continue;
1483
+ const id = method.id;
1484
+ if (typeof id !== "string") continue;
1485
+ if (id === didUrl) return method;
1486
+ if (fragment && (id === `#${fragment}` || id.endsWith(`#${fragment}`))) {
1487
+ return method;
1190
1488
  }
1191
- if (entry && typeof entry === "object") {
1192
- return entry;
1489
+ }
1490
+ return null;
1491
+ }
1492
+ function extractMethodIdsFromDidDocument(didDocument) {
1493
+ const methods = didDocument.verificationMethod;
1494
+ if (!Array.isArray(methods)) return [];
1495
+ return methods.filter((m) => m && typeof m.id === "string").map((m) => m.id);
1496
+ }
1497
+ async function resolveDidUrlToPublicKey(didUrl, options) {
1498
+ assertString(didUrl, "didUrl", "INVALID_DID_URL");
1499
+ const parsed = parseDidUrl(didUrl);
1500
+ const method = extractDidMethod(parsed.did);
1501
+ if (!method) {
1502
+ throw new OmaTrustError("INVALID_DID_URL", "Cannot extract DID method from DID URL", {
1503
+ didUrl,
1504
+ did: parsed.did
1505
+ });
1506
+ }
1507
+ switch (method) {
1508
+ case "web":
1509
+ return resolveDidUrlKey(parsed.didUrl, parsed.did, parsed.fragment, options);
1510
+ default:
1511
+ throw new OmaTrustError(
1512
+ "UNSUPPORTED_DID_METHOD",
1513
+ `DID URL key resolution is not supported for method "${method}"`,
1514
+ { didUrl, method }
1515
+ );
1516
+ }
1517
+ }
1518
+ async function resolveDidUrlKey(didUrl, did, fragment, options) {
1519
+ const domain = getDomainFromDidWeb(did);
1520
+ if (!domain) {
1521
+ throw new OmaTrustError("INVALID_DID_URL", "Cannot extract domain from did:web DID", {
1522
+ didUrl,
1523
+ did
1524
+ });
1525
+ }
1526
+ const fetchFn = options?.fetchDidDocument ?? fetchDidDocument;
1527
+ const didDocument = await fetchFn(domain);
1528
+ const method = findVerificationMethod(didDocument, didUrl, fragment);
1529
+ if (!method) {
1530
+ throw new OmaTrustError(
1531
+ "KEY_NOT_FOUND",
1532
+ `No verification method found matching "${fragment ? `#${fragment}` : didUrl}"`,
1533
+ { didUrl, fragment, availableMethods: extractMethodIdsFromDidDocument(didDocument) }
1534
+ );
1535
+ }
1536
+ const publicKeyJwk = method.publicKeyJwk;
1537
+ if (!publicKeyJwk || typeof publicKeyJwk !== "object") {
1538
+ throw new OmaTrustError(
1539
+ "KEY_NOT_FOUND",
1540
+ `Verification method "${method.id}" does not contain publicKeyJwk`,
1541
+ { didUrl, verificationMethodId: method.id }
1542
+ );
1543
+ }
1544
+ const validation = validatePublicJwk(publicKeyJwk);
1545
+ if (!validation.valid) {
1546
+ throw new OmaTrustError(
1547
+ "INVALID_JWK",
1548
+ `publicKeyJwk in verification method "${method.id}" is invalid: ${validation.error}`,
1549
+ { didUrl, verificationMethodId: method.id }
1550
+ );
1551
+ }
1552
+ return {
1553
+ didUrl,
1554
+ did,
1555
+ fragment,
1556
+ publicKeyJwk,
1557
+ verificationMethodId: method.id
1558
+ };
1559
+ }
1560
+
1561
+ // src/reputation/proof/x402-jws.ts
1562
+ var REQUIRED_OFFER_FIELDS = [
1563
+ "version",
1564
+ "resourceUrl",
1565
+ "scheme",
1566
+ "network",
1567
+ "asset",
1568
+ "payTo",
1569
+ "amount"
1570
+ ];
1571
+ var REQUIRED_RECEIPT_FIELDS = [
1572
+ "version",
1573
+ "network",
1574
+ "resourceUrl",
1575
+ "payer",
1576
+ "issuedAt"
1577
+ ];
1578
+ function validateOfferPayload(payload) {
1579
+ for (const field of REQUIRED_OFFER_FIELDS) {
1580
+ if (!(field in payload) || payload[field] === void 0 || payload[field] === null) {
1581
+ return { valid: false, field };
1193
1582
  }
1194
- return null;
1195
- }).filter((proof) => Boolean(proof?.proofType));
1583
+ }
1584
+ return { valid: true };
1196
1585
  }
1197
- function getProofPurpose(proof) {
1198
- if (proof.proofPurpose === "commercial-tx") {
1199
- return "commercial-tx";
1586
+ function validateReceiptPayload(payload) {
1587
+ for (const field of REQUIRED_RECEIPT_FIELDS) {
1588
+ if (!(field in payload) || payload[field] === void 0 || payload[field] === null) {
1589
+ return { valid: false, field };
1590
+ }
1200
1591
  }
1201
- return "shared-control";
1592
+ return { valid: true };
1202
1593
  }
1203
- function decodeJwtPayload(compactJws) {
1594
+ function failure(code, message, partial) {
1595
+ return {
1596
+ valid: false,
1597
+ error: { code, message },
1598
+ ...partial
1599
+ };
1600
+ }
1601
+ async function verifyX402JwsArtifact(artifact, options) {
1602
+ if (!artifact || typeof artifact !== "object") {
1603
+ return failure("INVALID_ARTIFACT", "Artifact must be a non-null object");
1604
+ }
1605
+ if (artifact.format !== "jws") {
1606
+ return failure("INVALID_ARTIFACT", `Expected format "jws", got "${artifact.format}"`);
1607
+ }
1608
+ if (typeof artifact.signature !== "string" || artifact.signature.length === 0) {
1609
+ return failure("INVALID_ARTIFACT", "Artifact signature must be a non-empty string");
1610
+ }
1611
+ const compactJws = artifact.signature;
1204
1612
  const parts = compactJws.split(".");
1205
1613
  if (parts.length !== 3) {
1206
- throw new OmaTrustError("PROOF_VERIFICATION_FAILED", "Invalid compact JWS format");
1614
+ return failure("MALFORMED_JWS", "Invalid compact JWS format: expected 3 dot-separated parts");
1207
1615
  }
1208
- const payloadB64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
1209
- const padded = payloadB64.padEnd(payloadB64.length + (4 - payloadB64.length % 4) % 4, "=");
1210
- let json;
1211
- if (typeof atob === "function") {
1212
- json = decodeURIComponent(
1213
- Array.from(atob(padded)).map((char) => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`).join("")
1616
+ let header;
1617
+ try {
1618
+ header = decodeProtectedHeader(compactJws);
1619
+ } catch {
1620
+ return failure("MALFORMED_JWS", "Failed to decode JWS protected header");
1621
+ }
1622
+ if (!header.alg || typeof header.alg !== "string") {
1623
+ return failure("MISSING_ALG", "JWS header must include alg", { header });
1624
+ }
1625
+ const kid = typeof header.kid === "string" ? header.kid : null;
1626
+ const embeddedJwk = header.jwk;
1627
+ if (!kid && !embeddedJwk) {
1628
+ return failure(
1629
+ "MISSING_KEY_MATERIAL",
1630
+ "JWS header must include at least one of kid or jwk",
1631
+ { header }
1214
1632
  );
1215
- } else {
1216
- json = Buffer.from(padded, "base64").toString("utf8");
1217
1633
  }
1218
- return JSON.parse(json);
1219
- }
1220
- async function verifyProof(params) {
1221
- const { proof, provider, expectedSubject, expectedController } = params;
1222
- try {
1223
- switch (proof.proofType) {
1224
- case "tx-encoded-value": {
1225
- if (!provider) {
1226
- return { valid: false, proofType: proof.proofType, reason: "Provider is required" };
1227
- }
1228
- if (!expectedSubject || !expectedController) {
1229
- return {
1230
- valid: false,
1231
- proofType: proof.proofType,
1232
- reason: "expectedSubject and expectedController are required"
1233
- };
1234
- }
1235
- const proofObject = proof.proofObject;
1236
- const chainId = parseChainId(proofObject.chainId);
1237
- const tx = await provider.getTransaction(
1238
- proofObject.txHash
1239
- );
1240
- if (!tx) {
1241
- return { valid: false, proofType: proof.proofType, reason: "Transaction not found" };
1242
- }
1243
- const expectedAmount = calculateTransferAmount(
1244
- expectedSubject,
1245
- expectedController,
1246
- chainId,
1247
- getProofPurpose(proof)
1248
- );
1249
- const subjectAddress = getAddress(extractAddressFromDid(expectedSubject));
1250
- const controllerAddress = getAddress(extractAddressFromDid(expectedController));
1251
- if (tx.from && getAddress(tx.from) !== subjectAddress) {
1252
- return { valid: false, proofType: proof.proofType, reason: "Transaction sender mismatch" };
1253
- }
1254
- if (tx.to && getAddress(tx.to) !== controllerAddress) {
1255
- return { valid: false, proofType: proof.proofType, reason: "Transaction recipient mismatch" };
1256
- }
1257
- if (BigInt(tx.value) !== expectedAmount) {
1258
- return { valid: false, proofType: proof.proofType, reason: "Transaction amount mismatch" };
1634
+ let publicKeyJwk;
1635
+ let publicKeySource;
1636
+ if (embeddedJwk) {
1637
+ const validation = validatePublicJwk(embeddedJwk);
1638
+ if (!validation.valid) {
1639
+ return failure(
1640
+ "INVALID_EMBEDDED_JWK",
1641
+ `Embedded JWK is invalid: ${validation.error}`,
1642
+ { header }
1643
+ );
1644
+ }
1645
+ publicKeyJwk = embeddedJwk;
1646
+ publicKeySource = "embedded-jwk";
1647
+ if (kid) {
1648
+ try {
1649
+ const resolved = await resolveDidUrlToPublicKey(kid, options?.resolveOptions);
1650
+ if (!publicJwkEquals(publicKeyJwk, resolved.publicKeyJwk)) {
1651
+ return failure(
1652
+ "KEY_CONFLICT",
1653
+ "Embedded jwk conflicts with public key resolved from kid",
1654
+ { header, kid }
1655
+ );
1259
1656
  }
1260
- return { valid: true, proofType: proof.proofType };
1657
+ } catch (err) {
1261
1658
  }
1262
- case "tx-interaction": {
1263
- if (!provider) {
1264
- return { valid: false, proofType: proof.proofType, reason: "Provider is required" };
1659
+ }
1660
+ } else {
1661
+ publicKeySource = "kid-resolution";
1662
+ try {
1663
+ const resolved = await resolveDidUrlToPublicKey(kid, options?.resolveOptions);
1664
+ publicKeyJwk = resolved.publicKeyJwk;
1665
+ } catch (err) {
1666
+ const message = err instanceof OmaTrustError ? `Failed to resolve kid "${kid}": ${err.message}` : `Failed to resolve kid "${kid}"`;
1667
+ return failure("KID_RESOLUTION_FAILED", message, { header, kid });
1668
+ }
1669
+ }
1670
+ let payload;
1671
+ try {
1672
+ const key = await importJWK(publicKeyJwk, header.alg);
1673
+ const result = await compactVerify(compactJws, key);
1674
+ const payloadText = new TextDecoder().decode(result.payload);
1675
+ payload = JSON.parse(payloadText);
1676
+ } catch (err) {
1677
+ const message = err instanceof Error ? err.message : "Signature verification failed";
1678
+ return failure("SIGNATURE_INVALID", message, { header, kid });
1679
+ }
1680
+ const publicKeyDid = jwkToDidJwk(publicKeyJwk);
1681
+ return {
1682
+ valid: true,
1683
+ header,
1684
+ payload,
1685
+ kid,
1686
+ publicKeyJwk,
1687
+ publicKeySource,
1688
+ publicKeyDid
1689
+ };
1690
+ }
1691
+ async function verifyX402JwsOffer(artifact, options) {
1692
+ const result = await verifyX402JwsArtifact(artifact, options);
1693
+ if (!result.valid) return result;
1694
+ const payloadCheck = validateOfferPayload(result.payload);
1695
+ if (!payloadCheck.valid) {
1696
+ return failure(
1697
+ "INVALID_OFFER_PAYLOAD",
1698
+ `Missing required offer field: ${payloadCheck.field}`,
1699
+ {
1700
+ header: result.header,
1701
+ payload: result.payload,
1702
+ kid: result.kid,
1703
+ publicKeyJwk: result.publicKeyJwk,
1704
+ publicKeySource: result.publicKeySource,
1705
+ publicKeyDid: result.publicKeyDid
1706
+ }
1707
+ );
1708
+ }
1709
+ return result;
1710
+ }
1711
+ async function verifyX402JwsReceipt(artifact, options) {
1712
+ const result = await verifyX402JwsArtifact(artifact, options);
1713
+ if (!result.valid) return result;
1714
+ const payloadCheck = validateReceiptPayload(result.payload);
1715
+ if (!payloadCheck.valid) {
1716
+ return failure(
1717
+ "INVALID_RECEIPT_PAYLOAD",
1718
+ `Missing required receipt field: ${payloadCheck.field}`,
1719
+ {
1720
+ header: result.header,
1721
+ payload: result.payload,
1722
+ kid: result.kid,
1723
+ publicKeyJwk: result.publicKeyJwk,
1724
+ publicKeySource: result.publicKeySource,
1725
+ publicKeyDid: result.publicKeyDid
1726
+ }
1727
+ );
1728
+ }
1729
+ return result;
1730
+ }
1731
+ var OFFER_DOMAIN = {
1732
+ name: "x402 offer",
1733
+ version: "1",
1734
+ chainId: 1
1735
+ };
1736
+ var RECEIPT_DOMAIN = {
1737
+ name: "x402 receipt",
1738
+ version: "1",
1739
+ chainId: 1
1740
+ };
1741
+ var OFFER_TYPES = {
1742
+ Offer: [
1743
+ { name: "version", type: "uint256" },
1744
+ { name: "resourceUrl", type: "string" },
1745
+ { name: "scheme", type: "string" },
1746
+ { name: "network", type: "string" },
1747
+ { name: "asset", type: "string" },
1748
+ { name: "payTo", type: "string" },
1749
+ { name: "amount", type: "string" },
1750
+ { name: "validUntil", type: "uint256" }
1751
+ ]
1752
+ };
1753
+ var RECEIPT_TYPES = {
1754
+ Receipt: [
1755
+ { name: "version", type: "uint256" },
1756
+ { name: "network", type: "string" },
1757
+ { name: "resourceUrl", type: "string" },
1758
+ { name: "payer", type: "string" },
1759
+ { name: "issuedAt", type: "uint256" },
1760
+ { name: "transaction", type: "string" }
1761
+ ]
1762
+ };
1763
+ var REQUIRED_OFFER_FIELDS2 = [
1764
+ "version",
1765
+ "resourceUrl",
1766
+ "scheme",
1767
+ "network",
1768
+ "asset",
1769
+ "payTo",
1770
+ "amount"
1771
+ ];
1772
+ var REQUIRED_RECEIPT_FIELDS2 = [
1773
+ "version",
1774
+ "network",
1775
+ "resourceUrl",
1776
+ "payer",
1777
+ "issuedAt"
1778
+ ];
1779
+ function validateOfferPayload2(payload) {
1780
+ for (const field of REQUIRED_OFFER_FIELDS2) {
1781
+ if (!(field in payload) || payload[field] === void 0 || payload[field] === null) {
1782
+ return { valid: false, field };
1783
+ }
1784
+ }
1785
+ return { valid: true };
1786
+ }
1787
+ function validateReceiptPayload2(payload) {
1788
+ for (const field of REQUIRED_RECEIPT_FIELDS2) {
1789
+ if (!(field in payload) || payload[field] === void 0 || payload[field] === null) {
1790
+ return { valid: false, field };
1791
+ }
1792
+ }
1793
+ return { valid: true };
1794
+ }
1795
+ function failure2(code, message, partial) {
1796
+ return {
1797
+ valid: false,
1798
+ error: { code, message },
1799
+ ...partial
1800
+ };
1801
+ }
1802
+ function prepareOfferMessage(payload) {
1803
+ return {
1804
+ version: payload.version,
1805
+ resourceUrl: payload.resourceUrl,
1806
+ scheme: payload.scheme,
1807
+ network: payload.network,
1808
+ asset: payload.asset,
1809
+ payTo: payload.payTo,
1810
+ amount: payload.amount,
1811
+ validUntil: payload.validUntil ?? 0
1812
+ };
1813
+ }
1814
+ function prepareReceiptMessage(payload) {
1815
+ return {
1816
+ version: payload.version,
1817
+ network: payload.network,
1818
+ resourceUrl: payload.resourceUrl,
1819
+ payer: payload.payer,
1820
+ issuedAt: payload.issuedAt,
1821
+ transaction: payload.transaction ?? ""
1822
+ };
1823
+ }
1824
+ function verifyX402Eip712Artifact(artifact, artifactType) {
1825
+ if (!artifact || typeof artifact !== "object") {
1826
+ return failure2("INVALID_ARTIFACT", "Artifact must be a non-null object");
1827
+ }
1828
+ if (artifact.format !== "eip712") {
1829
+ return failure2("INVALID_ARTIFACT", `Expected format "eip712", got "${artifact.format}"`);
1830
+ }
1831
+ if (!artifact.payload || typeof artifact.payload !== "object" || Array.isArray(artifact.payload)) {
1832
+ return failure2("MISSING_PAYLOAD", "EIP-712 artifact must include a payload object");
1833
+ }
1834
+ if (typeof artifact.signature !== "string" || artifact.signature.length === 0) {
1835
+ return failure2("MISSING_SIGNATURE", "EIP-712 artifact must include a non-empty signature");
1836
+ }
1837
+ const payload = artifact.payload;
1838
+ if (artifactType === "offer") {
1839
+ const check = validateOfferPayload2(payload);
1840
+ if (!check.valid) {
1841
+ return failure2(
1842
+ "INVALID_OFFER_PAYLOAD",
1843
+ `Missing required offer field: ${check.field}`,
1844
+ { payload }
1845
+ );
1846
+ }
1847
+ } else {
1848
+ const check = validateReceiptPayload2(payload);
1849
+ if (!check.valid) {
1850
+ return failure2(
1851
+ "INVALID_RECEIPT_PAYLOAD",
1852
+ `Missing required receipt field: ${check.field}`,
1853
+ { payload }
1854
+ );
1855
+ }
1856
+ }
1857
+ const domain = artifactType === "offer" ? OFFER_DOMAIN : RECEIPT_DOMAIN;
1858
+ const types = artifactType === "offer" ? OFFER_TYPES : RECEIPT_TYPES;
1859
+ const message = artifactType === "offer" ? prepareOfferMessage(payload) : prepareReceiptMessage(payload);
1860
+ let signer;
1861
+ try {
1862
+ signer = verifyTypedData(
1863
+ domain,
1864
+ types,
1865
+ message,
1866
+ artifact.signature
1867
+ );
1868
+ signer = getAddress(signer);
1869
+ } catch (err) {
1870
+ const message2 = err instanceof Error ? err.message : "EIP-712 signature verification failed";
1871
+ return failure2("SIGNATURE_INVALID", message2, { payload });
1872
+ }
1873
+ return {
1874
+ valid: true,
1875
+ payload,
1876
+ signer,
1877
+ artifactType
1878
+ };
1879
+ }
1880
+ function verifyX402Eip712Offer(artifact) {
1881
+ return verifyX402Eip712Artifact(artifact, "offer");
1882
+ }
1883
+ function verifyX402Eip712Receipt(artifact) {
1884
+ return verifyX402Eip712Artifact(artifact, "receipt");
1885
+ }
1886
+
1887
+ // src/reputation/verify.ts
1888
+ function parseChainId(input) {
1889
+ if (typeof input === "number") {
1890
+ return input;
1891
+ }
1892
+ if (typeof input === "string") {
1893
+ if (input.includes(":")) {
1894
+ const [, chainId] = input.split(":");
1895
+ return Number(chainId);
1896
+ }
1897
+ return Number(input);
1898
+ }
1899
+ return NaN;
1900
+ }
1901
+ function parseProofs(attestation) {
1902
+ const rawProofs = attestation.data.proofs;
1903
+ if (!Array.isArray(rawProofs)) {
1904
+ return [];
1905
+ }
1906
+ return rawProofs.map((entry) => {
1907
+ if (typeof entry === "string") {
1908
+ try {
1909
+ return JSON.parse(entry);
1910
+ } catch {
1911
+ return null;
1912
+ }
1913
+ }
1914
+ if (entry && typeof entry === "object") {
1915
+ return entry;
1916
+ }
1917
+ return null;
1918
+ }).filter((proof) => Boolean(proof?.proofType));
1919
+ }
1920
+ function getProofPurpose(proof) {
1921
+ if (proof.proofPurpose === "commercial-tx") {
1922
+ return "commercial-tx";
1923
+ }
1924
+ return "shared-control";
1925
+ }
1926
+ function decodeJwtPayload(compactJws) {
1927
+ const parts = compactJws.split(".");
1928
+ if (parts.length !== 3) {
1929
+ throw new OmaTrustError("PROOF_VERIFICATION_FAILED", "Invalid compact JWS format");
1930
+ }
1931
+ const payloadB64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
1932
+ const padded = payloadB64.padEnd(payloadB64.length + (4 - payloadB64.length % 4) % 4, "=");
1933
+ let json;
1934
+ if (typeof atob === "function") {
1935
+ json = decodeURIComponent(
1936
+ Array.from(atob(padded)).map((char) => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`).join("")
1937
+ );
1938
+ } else {
1939
+ json = Buffer.from(padded, "base64").toString("utf8");
1940
+ }
1941
+ return JSON.parse(json);
1942
+ }
1943
+ async function verifyProof(params) {
1944
+ const { proof, provider, expectedSubjectDid, expectedControllerDid } = params;
1945
+ try {
1946
+ switch (proof.proofType) {
1947
+ case "tx-encoded-value": {
1948
+ if (!provider) {
1949
+ return { valid: false, proofType: proof.proofType, reason: "Provider is required" };
1950
+ }
1951
+ if (!expectedSubjectDid || !expectedControllerDid) {
1952
+ return {
1953
+ valid: false,
1954
+ proofType: proof.proofType,
1955
+ reason: "expectedSubjectDid and expectedControllerDid are required"
1956
+ };
1957
+ }
1958
+ const proofObject = proof.proofObject;
1959
+ const chainId = parseChainId(proofObject.chainId);
1960
+ const tx = await provider.getTransaction(
1961
+ proofObject.txHash
1962
+ );
1963
+ if (!tx) {
1964
+ return { valid: false, proofType: proof.proofType, reason: "Transaction not found" };
1965
+ }
1966
+ const expectedAmount = calculateTransferAmount(
1967
+ expectedSubjectDid,
1968
+ expectedControllerDid,
1969
+ chainId,
1970
+ getProofPurpose(proof)
1971
+ );
1972
+ const subjectAddress = getAddress(extractAddressFromDid(expectedSubjectDid));
1973
+ const controllerAddress = getAddress(extractAddressFromDid(expectedControllerDid));
1974
+ if (tx.from && getAddress(tx.from) !== subjectAddress) {
1975
+ return { valid: false, proofType: proof.proofType, reason: "Transaction sender mismatch" };
1976
+ }
1977
+ if (tx.to && getAddress(tx.to) !== controllerAddress) {
1978
+ return { valid: false, proofType: proof.proofType, reason: "Transaction recipient mismatch" };
1979
+ }
1980
+ if (BigInt(tx.value) !== expectedAmount) {
1981
+ return { valid: false, proofType: proof.proofType, reason: "Transaction amount mismatch" };
1982
+ }
1983
+ return { valid: true, proofType: proof.proofType };
1984
+ }
1985
+ case "tx-interaction": {
1986
+ if (!provider) {
1987
+ return { valid: false, proofType: proof.proofType, reason: "Provider is required" };
1265
1988
  }
1266
1989
  const proofObject = proof.proofObject;
1267
1990
  const tx = await provider.getTransaction(
@@ -1321,6 +2044,38 @@ async function verifyProof(params) {
1321
2044
  if (!proof.proofObject || typeof proof.proofObject !== "object") {
1322
2045
  return { valid: false, proofType: proof.proofType, reason: "Invalid x402 proof object" };
1323
2046
  }
2047
+ const proofObj = proof.proofObject;
2048
+ if (proofObj.format === "jws" && typeof proofObj.signature === "string") {
2049
+ const artifact = {
2050
+ format: "jws",
2051
+ signature: proofObj.signature
2052
+ };
2053
+ const jwsResult = proof.proofType === "x402-offer" ? await verifyX402JwsOffer(artifact) : await verifyX402JwsReceipt(artifact);
2054
+ if (!jwsResult.valid) {
2055
+ return {
2056
+ valid: false,
2057
+ proofType: proof.proofType,
2058
+ reason: jwsResult.error?.message ?? "JWS verification failed"
2059
+ };
2060
+ }
2061
+ return { valid: true, proofType: proof.proofType };
2062
+ }
2063
+ if (proofObj.format === "eip712" && typeof proofObj.signature === "string" && proofObj.payload && typeof proofObj.payload === "object") {
2064
+ const artifact = {
2065
+ format: "eip712",
2066
+ payload: proofObj.payload,
2067
+ signature: proofObj.signature
2068
+ };
2069
+ const eip712Result = proof.proofType === "x402-offer" ? verifyX402Eip712Offer(artifact) : verifyX402Eip712Receipt(artifact);
2070
+ if (!eip712Result.valid) {
2071
+ return {
2072
+ valid: false,
2073
+ proofType: proof.proofType,
2074
+ reason: eip712Result.error?.message ?? "EIP-712 verification failed"
2075
+ };
2076
+ }
2077
+ return { valid: true, proofType: proof.proofType };
2078
+ }
1324
2079
  return { valid: true, proofType: proof.proofType };
1325
2080
  }
1326
2081
  case "evidence-pointer": {
@@ -1332,9 +2087,9 @@ async function verifyProof(params) {
1332
2087
  if (!response.ok) {
1333
2088
  return { valid: false, proofType: proof.proofType, reason: `Evidence fetch failed (${response.status})` };
1334
2089
  }
1335
- if (object.url.endsWith("/.well-known/did.json") && expectedController) {
2090
+ if (object.url.endsWith("/.well-known/did.json") && expectedControllerDid) {
1336
2091
  const didDoc = await response.json();
1337
- const didCheck = verifyDidDocumentControllerDid(didDoc, expectedController);
2092
+ const didCheck = verifyDidDocumentControllerDid(didDoc, expectedControllerDid);
1338
2093
  return {
1339
2094
  valid: didCheck.valid,
1340
2095
  proofType: proof.proofType,
@@ -1342,10 +2097,10 @@ async function verifyProof(params) {
1342
2097
  };
1343
2098
  }
1344
2099
  const body = await response.text();
1345
- if (expectedController && !body.includes(expectedController)) {
2100
+ if (expectedControllerDid && !body.includes(expectedControllerDid)) {
1346
2101
  try {
1347
2102
  const parsed = parseDnsTxtRecord(body);
1348
- if (parsed.controller !== expectedController) {
2103
+ if (!parsed.controllers.includes(expectedControllerDid)) {
1349
2104
  return {
1350
2105
  valid: false,
1351
2106
  proofType: proof.proofType,
@@ -1401,8 +2156,8 @@ async function verifyAttestation(params) {
1401
2156
  const result = await verifyProof({
1402
2157
  proof,
1403
2158
  provider: params.provider,
1404
- expectedSubject: params.context?.subject,
1405
- expectedController: params.context?.controller
2159
+ expectedSubjectDid: params.context?.subjectDid,
2160
+ expectedControllerDid: params.context?.controllerDid
1406
2161
  });
1407
2162
  checks[proof.proofType] = result.valid;
1408
2163
  if (!result.valid) {
@@ -1485,25 +2240,523 @@ async function callMethod(params, method) {
1485
2240
  if (!response.ok) {
1486
2241
  return null;
1487
2242
  }
1488
- return {
1489
- ok: true,
1490
- method,
1491
- details
1492
- };
2243
+ return {
2244
+ ok: true,
2245
+ method,
2246
+ details
2247
+ };
2248
+ }
2249
+ async function callControllerWitness(params) {
2250
+ const dnsResult = await callMethod(params, "dns-txt").catch(() => null);
2251
+ if (dnsResult) {
2252
+ return dnsResult;
2253
+ }
2254
+ const didJsonResult = await callMethod(params, "did-json").catch(() => null);
2255
+ if (didJsonResult) {
2256
+ return didJsonResult;
2257
+ }
2258
+ return {
2259
+ ok: false,
2260
+ method: "did-json"
2261
+ };
2262
+ }
2263
+ var DEFAULT_CONTROLLER_WITNESS_URL = "https://api.omatrust.org/v1/controller-witness";
2264
+ async function requestControllerWitness(params) {
2265
+ const url = params.gatewayUrl ?? DEFAULT_CONTROLLER_WITNESS_URL;
2266
+ const body = {
2267
+ subjectDid: params.subjectDid,
2268
+ controllerDid: params.controllerDid
2269
+ };
2270
+ if (params.chainId !== void 0) {
2271
+ body.chainId = params.chainId;
2272
+ }
2273
+ let response;
2274
+ try {
2275
+ response = await fetch(url, {
2276
+ method: "POST",
2277
+ headers: { "Content-Type": "application/json" },
2278
+ credentials: "include",
2279
+ body: JSON.stringify(body),
2280
+ signal: AbortSignal.timeout(params.timeoutMs ?? 15e3)
2281
+ });
2282
+ } catch (err) {
2283
+ throw new OmaTrustError("NETWORK_ERROR", "Controller witness request failed", { err });
2284
+ }
2285
+ if (!response.ok) {
2286
+ const errorBody = await response.json().catch(() => ({ error: response.statusText }));
2287
+ throw new OmaTrustError(
2288
+ "API_ERROR",
2289
+ errorBody.error ?? `Controller witness failed: ${response.status}`,
2290
+ { status: response.status, ...errorBody }
2291
+ );
2292
+ }
2293
+ return await response.json();
2294
+ }
2295
+ var EIP1967_ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
2296
+ var OWNERSHIP_PATTERNS = [
2297
+ { method: "owner", signature: "function owner() view returns (address)" },
2298
+ { method: "admin", signature: "function admin() view returns (address)" },
2299
+ { method: "getOwner", signature: "function getOwner() view returns (address)" }
2300
+ ];
2301
+ async function readOwnerFromContract(provider, contractAddress, signature, method) {
2302
+ try {
2303
+ const iface = new Interface([signature]);
2304
+ const data = iface.encodeFunctionData(method, []);
2305
+ const result = await provider.call({ to: contractAddress, data });
2306
+ const [value] = iface.decodeFunctionResult(method, result);
2307
+ if (typeof value === "string" && isAddress(value) && value !== ZeroAddress) {
2308
+ return getAddress(value);
2309
+ }
2310
+ } catch {
2311
+ }
2312
+ return null;
2313
+ }
2314
+ async function discoverContractOwner(provider, contractAddress) {
2315
+ try {
2316
+ const code = await provider.getCode(contractAddress);
2317
+ if (code === "0x" || code === "0x0") {
2318
+ return null;
2319
+ }
2320
+ } catch {
2321
+ return null;
2322
+ }
2323
+ for (const pattern of OWNERSHIP_PATTERNS) {
2324
+ const address = await readOwnerFromContract(
2325
+ provider,
2326
+ contractAddress,
2327
+ pattern.signature,
2328
+ pattern.method
2329
+ );
2330
+ if (address) {
2331
+ return address;
2332
+ }
2333
+ }
2334
+ try {
2335
+ const adminValue = await provider.getStorage(contractAddress, EIP1967_ADMIN_SLOT);
2336
+ if (adminValue && adminValue !== "0x" && adminValue !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
2337
+ const adminAddress = getAddress(`0x${adminValue.slice(-40)}`);
2338
+ if (adminAddress !== ZeroAddress) {
2339
+ return adminAddress;
2340
+ }
2341
+ }
2342
+ } catch {
2343
+ }
2344
+ return null;
2345
+ }
2346
+ async function discoverControllingWalletDid(provider, contractAddress, chainId) {
2347
+ const owner = await discoverContractOwner(provider, contractAddress);
2348
+ return owner ? buildEvmDidPkh(chainId, owner) : null;
2349
+ }
2350
+ async function verifyTransferProof(provider, txHash, subjectDid, attesterAddress, chainId) {
2351
+ try {
2352
+ const tx = await provider.getTransaction(txHash);
2353
+ if (!tx || !tx.from || !tx.to) {
2354
+ return false;
2355
+ }
2356
+ if (getAddress(tx.to) !== getAddress(attesterAddress)) {
2357
+ return false;
2358
+ }
2359
+ const attesterDid = buildEvmDidPkh(chainId, attesterAddress);
2360
+ const expectedAmount = calculateTransferAmount(
2361
+ subjectDid,
2362
+ attesterDid,
2363
+ chainId,
2364
+ "shared-control"
2365
+ );
2366
+ const actualValue = BigInt(tx.value ?? 0n);
2367
+ return actualValue === expectedAmount;
2368
+ } catch {
2369
+ return false;
2370
+ }
2371
+ }
2372
+
2373
+ // src/identity/controller-id.ts
2374
+ function isSameControllerId(a, b) {
2375
+ let normalizedA = null;
2376
+ let normalizedB = null;
2377
+ try {
2378
+ normalizedA = normalizeDid(a);
2379
+ } catch {
2380
+ }
2381
+ try {
2382
+ normalizedB = normalizeDid(b);
2383
+ } catch {
2384
+ }
2385
+ if (normalizedA && normalizedB && normalizedA === normalizedB) {
2386
+ return true;
2387
+ }
2388
+ const evmA = extractControllerEvmAddress(a);
2389
+ const evmB = extractControllerEvmAddress(b);
2390
+ if (evmA && evmB && evmA.toLowerCase() === evmB.toLowerCase()) {
2391
+ return true;
2392
+ }
2393
+ const methodA = extractDidMethod(a);
2394
+ const methodB = extractDidMethod(b);
2395
+ if (methodA === "jwk" && methodB === "jwk") {
2396
+ try {
2397
+ const jwkA = didJwkToJwk(a);
2398
+ const jwkB = didJwkToJwk(b);
2399
+ return publicJwkEquals(jwkA, jwkB);
2400
+ } catch {
2401
+ return false;
2402
+ }
2403
+ }
2404
+ return false;
2405
+ }
2406
+ function extractControllerEvmAddress(controllerDid) {
2407
+ try {
2408
+ const method = extractDidMethod(controllerDid);
2409
+ if (method === "pkh" && controllerDid.includes("eip155")) {
2410
+ return extractAddressFromDid(controllerDid);
2411
+ }
2412
+ } catch {
2413
+ }
2414
+ return null;
2415
+ }
2416
+
2417
+ // src/shared/trust-anchors.ts
2418
+ var DEFAULT_TRUST_ANCHORS_URL = "https://api.omatrust.org/v1/trust-anchors";
2419
+ var TRUST_ANCHORS_URL = DEFAULT_TRUST_ANCHORS_URL;
2420
+ var cachedAnchors = null;
2421
+ var cacheTimestamp = 0;
2422
+ var CACHE_TTL_MS = 5 * 60 * 1e3;
2423
+ async function fetchTrustAnchors(url) {
2424
+ const now = Date.now();
2425
+ if (cachedAnchors && now - cacheTimestamp < CACHE_TTL_MS) {
2426
+ return cachedAnchors;
2427
+ }
2428
+ let res;
2429
+ try {
2430
+ res = await fetch(url ?? TRUST_ANCHORS_URL);
2431
+ } catch (err) {
2432
+ throw new OmaTrustError("NETWORK_ERROR", "Failed to fetch trust anchors", { err });
2433
+ }
2434
+ if (!res.ok) {
2435
+ throw new OmaTrustError("NETWORK_ERROR", `Failed to fetch trust anchors: ${res.status} ${res.statusText}`);
2436
+ }
2437
+ const anchors = await res.json();
2438
+ if (!anchors.version || !anchors.chains || typeof anchors.chains !== "object") {
2439
+ throw new OmaTrustError("INVALID_INPUT", "Invalid trust anchors format");
2440
+ }
2441
+ cachedAnchors = anchors;
2442
+ cacheTimestamp = now;
2443
+ return anchors;
2444
+ }
2445
+ function getChainAnchors(anchors, caip2) {
2446
+ const chain = anchors.chains[caip2];
2447
+ if (!chain) {
2448
+ throw new OmaTrustError("UNSUPPORTED_CHAIN", `Chain ${caip2} is not in the trust anchors`, {
2449
+ caip2,
2450
+ supportedChains: Object.keys(anchors.chains)
2451
+ });
2452
+ }
2453
+ return chain;
2454
+ }
2455
+
2456
+ // src/reputation/proof/dns-txt-shared.ts
2457
+ async function verifyDnsTxtControllerDid(domain, expectedControllerDid, options = {}) {
2458
+ if (!domain || typeof domain !== "string") {
2459
+ throw new OmaTrustError("INVALID_INPUT", "domain must be a non-empty string", { domain });
2460
+ }
2461
+ if (!options.resolveTxt) {
2462
+ throw new OmaTrustError("NETWORK_ERROR", "No DNS TXT resolver was provided", { domain });
2463
+ }
2464
+ const prefix = options.recordPrefix ?? "_controllers";
2465
+ const host = `${prefix}.${domain.toLowerCase().replace(/\.$/, "")}`;
2466
+ let records;
2467
+ try {
2468
+ records = await options.resolveTxt(host);
2469
+ } catch (err) {
2470
+ throw new OmaTrustError("NETWORK_ERROR", "Failed to resolve DNS TXT records", { domain, err });
2471
+ }
2472
+ for (const recordParts of records) {
2473
+ const record = recordParts.join("");
2474
+ const parsed = parseDnsTxtRecord(record);
2475
+ if (parsed.version !== "1") continue;
2476
+ for (const recordController of parsed.controllers) {
2477
+ if (isSameControllerId(recordController, expectedControllerDid)) {
2478
+ return { valid: true, record };
2479
+ }
2480
+ }
2481
+ }
2482
+ return { valid: false, reason: "Controller DID not found in DNS TXT records" };
2483
+ }
2484
+
2485
+ // src/reputation/attester-authorization.ts
2486
+ var DEFAULT_CHAIN = "eip155:6623";
2487
+ var DEFAULT_PURPOSES = ["authentication", "assertionMethod"];
2488
+ async function getControllerAuthorization(params) {
2489
+ const chain = params.chain ?? DEFAULT_CHAIN;
2490
+ const purposes = params.purpose && params.purpose.length > 0 ? params.purpose : DEFAULT_PURPOSES;
2491
+ const controllerDid = normalizeDid(params.controllerDid);
2492
+ const controllerMethod = extractDidMethod(controllerDid);
2493
+ const controllerEvmAddress = extractControllerEvmAddress(controllerDid);
2494
+ const anchors = await fetchTrustAnchors();
2495
+ const chainAnchors = getChainAnchors(anchors, chain);
2496
+ const easContractAddress = params.easContractAddress ?? chainAnchors.easContract;
2497
+ const provider = params.provider;
2498
+ const controllerWitnessSchemaUid = chainAnchors.schemas["controller-witness"];
2499
+ const keyBindingSchemaUid = chainAnchors.schemas["key-binding"];
2500
+ const subjectAddress = didToAddress(params.subjectDid);
2501
+ let relevantWitnesses = [];
2502
+ if (controllerWitnessSchemaUid) {
2503
+ const rawWitnesses = await queryByRecipientAndSchema(
2504
+ easContractAddress,
2505
+ provider,
2506
+ subjectAddress,
2507
+ [controllerWitnessSchemaUid],
2508
+ params.fromBlock ?? 0
2509
+ );
2510
+ relevantWitnesses = rawWitnesses.filter((att) => {
2511
+ const witnessController = att.data?.controller;
2512
+ if (typeof witnessController !== "string") return false;
2513
+ return isSameControllerId(witnessController, controllerDid);
2514
+ });
2515
+ relevantWitnesses.sort((a, b) => Number(a.time - b.time));
2516
+ }
2517
+ const controllerWitnesses = relevantWitnesses.map((att) => ({
2518
+ uid: att.uid,
2519
+ issuedAt: att.time,
2520
+ attester: att.attester,
2521
+ method: resolveWitnessMethod(att.data?.method)
2522
+ }));
2523
+ let keyBindingUid = null;
2524
+ let until = null;
2525
+ let keyPurposeStatus = "not-required";
2526
+ if (keyBindingSchemaUid) {
2527
+ const keyBindings = await queryByRecipientAndSchema(
2528
+ easContractAddress,
2529
+ provider,
2530
+ subjectAddress,
2531
+ [keyBindingSchemaUid],
2532
+ params.fromBlock ?? 0
2533
+ );
2534
+ const relevantKeyBindings = keyBindings.filter((att) => controllerMatchesKeyBinding(att, controllerDid, controllerMethod)).sort((a, b) => Number(b.time - a.time));
2535
+ const relevantKeyBinding = relevantKeyBindings[0] ?? null;
2536
+ if (relevantKeyBinding) {
2537
+ keyBindingUid = relevantKeyBinding.uid;
2538
+ if (relevantKeyBinding.revocationTime > 0n) {
2539
+ until = relevantKeyBinding.revocationTime;
2540
+ }
2541
+ const keyPurposes = relevantKeyBinding.data?.keyPurpose;
2542
+ if (!Array.isArray(keyPurposes) || keyPurposes.length === 0) {
2543
+ keyPurposeStatus = "unknown";
2544
+ } else {
2545
+ const allMatched = purposes.every((p) => keyPurposes.includes(p));
2546
+ keyPurposeStatus = allMatched ? "matched" : "mismatch";
2547
+ }
2548
+ }
2549
+ }
2550
+ let currentlyVerified = false;
2551
+ let liveMethod = null;
2552
+ let transferProofVerified = false;
2553
+ let transferProofAnchor = null;
2554
+ const subjectMethod = extractDidMethod(params.subjectDid);
2555
+ if (subjectMethod === "web") {
2556
+ const domain = getDomainFromDidWeb(params.subjectDid);
2557
+ if (domain) {
2558
+ try {
2559
+ const dnsResult = await verifyDnsTxtControllerDid(domain, controllerDid, {
2560
+ resolveTxt: params.resolveTxt
2561
+ });
2562
+ if (dnsResult.valid) {
2563
+ currentlyVerified = true;
2564
+ liveMethod = "dns";
2565
+ }
2566
+ } catch {
2567
+ }
2568
+ if (!currentlyVerified) {
2569
+ try {
2570
+ const fetchDoc = params.fetchDidDocument ?? fetchDidDocument;
2571
+ const didDoc = await fetchDoc(domain);
2572
+ const didJsonResult = verifyDidDocumentControllerDid(didDoc, controllerDid);
2573
+ if (didJsonResult.valid) {
2574
+ currentlyVerified = true;
2575
+ liveMethod = "did-document";
2576
+ }
2577
+ } catch {
2578
+ }
2579
+ }
2580
+ }
2581
+ } else if (subjectMethod === "pkh") {
2582
+ if (isEvmDidPkh(params.subjectDid) && controllerEvmAddress) {
2583
+ const subjectContractAddress = getAddressFromDidPkh(params.subjectDid);
2584
+ const subjectChainId = getChainIdFromDidPkh(params.subjectDid);
2585
+ const chainIdNum = subjectChainId ? Number(subjectChainId) : null;
2586
+ if (subjectContractAddress && chainIdNum) {
2587
+ const ownerAddress = await discoverContractOwner(
2588
+ provider,
2589
+ subjectContractAddress
2590
+ );
2591
+ if (ownerAddress && getAddress(ownerAddress) === getAddress(controllerEvmAddress)) {
2592
+ currentlyVerified = true;
2593
+ liveMethod = "contract-ownership";
2594
+ }
2595
+ if (!currentlyVerified && keyBindingUid) {
2596
+ const relevantKeyBinding = await findKeyBindingWithTransferProof(
2597
+ keyBindingSchemaUid,
2598
+ easContractAddress,
2599
+ provider,
2600
+ subjectAddress,
2601
+ controllerDid,
2602
+ controllerMethod,
2603
+ params.fromBlock ?? 0
2604
+ );
2605
+ if (relevantKeyBinding) {
2606
+ const proofTxHash = relevantKeyBinding.data?.proofTxHash;
2607
+ if (proofTxHash && /^0x[0-9a-fA-F]{64}$/.test(proofTxHash)) {
2608
+ const verified = await verifyTransferProof(
2609
+ provider,
2610
+ proofTxHash,
2611
+ params.subjectDid,
2612
+ controllerEvmAddress,
2613
+ chainIdNum
2614
+ );
2615
+ if (verified) {
2616
+ transferProofVerified = true;
2617
+ transferProofAnchor = relevantKeyBinding.time;
2618
+ }
2619
+ }
2620
+ }
2621
+ }
2622
+ }
2623
+ }
2624
+ }
2625
+ const witnessAnchor = relevantWitnesses.length > 0 ? relevantWitnesses[0].time : null;
2626
+ const anchoredFrom = witnessAnchor ?? transferProofAnchor;
2627
+ const purposeBlocks = keyPurposeStatus === "mismatch";
2628
+ const hasOpenWindow = relevantWitnesses.length > 0 && until === null;
2629
+ const hasKeyBindingWithProof = keyBindingUid !== null && transferProofVerified && until === null;
2630
+ const authorized = !purposeBlocks && (hasOpenWindow || currentlyVerified && until === null || hasKeyBindingWithProof);
2631
+ return {
2632
+ authorized,
2633
+ anchoredFrom,
2634
+ until,
2635
+ currentlyVerified,
2636
+ liveMethod,
2637
+ controllerWitnesses,
2638
+ keyBindingUid,
2639
+ keyPurposeStatus,
2640
+ transferProofVerified: transferProofVerified || void 0
2641
+ };
2642
+ }
2643
+ function controllerMatchesKeyBinding(att, controllerDid, controllerMethod) {
2644
+ const keyId = att.data?.keyId;
2645
+ if (typeof keyId === "string") {
2646
+ if (isSameControllerId(keyId, controllerDid)) {
2647
+ return true;
2648
+ }
2649
+ }
2650
+ if (controllerMethod === "jwk") {
2651
+ const publicKeyJwkRaw = att.data?.publicKeyJwk;
2652
+ if (publicKeyJwkRaw) {
2653
+ try {
2654
+ const onChainJwk = typeof publicKeyJwkRaw === "string" ? JSON.parse(publicKeyJwkRaw) : publicKeyJwkRaw;
2655
+ const controllerJwk = didJwkToJwk(controllerDid);
2656
+ return publicJwkEquals(onChainJwk, controllerJwk);
2657
+ } catch {
2658
+ }
2659
+ }
2660
+ }
2661
+ return false;
2662
+ }
2663
+ var EAS_EVENT_ABI2 = [
2664
+ "event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID)"
2665
+ ];
2666
+ function resolveWitnessMethod(value) {
2667
+ if (typeof value !== "string") return void 0;
2668
+ switch (value) {
2669
+ case "dns":
2670
+ case "dns-txt":
2671
+ return "dns";
2672
+ case "did-document":
2673
+ case "did-json":
2674
+ return "did-document";
2675
+ case "manual":
2676
+ return "manual";
2677
+ default:
2678
+ return "other";
2679
+ }
1493
2680
  }
1494
- async function callControllerWitness(params) {
1495
- const dnsResult = await callMethod(params, "dns-txt").catch(() => null);
1496
- if (dnsResult) {
1497
- return dnsResult;
2681
+ async function queryByRecipientAndSchema(easContractAddress, provider, recipient, schemas, fromBlock) {
2682
+ const contract = new Contract(easContractAddress, EAS_EVENT_ABI2, provider);
2683
+ const filter = contract.filters.Attested(recipient, null);
2684
+ const toBlock = await provider.getBlockNumber();
2685
+ let events;
2686
+ try {
2687
+ events = await contract.queryFilter(filter, fromBlock, toBlock);
2688
+ } catch (err) {
2689
+ throw new OmaTrustError("NETWORK_ERROR", "Failed to query attestation events", { err });
1498
2690
  }
1499
- const didJsonResult = await callMethod(params, "did-json").catch(() => null);
1500
- if (didJsonResult) {
1501
- return didJsonResult;
2691
+ const eas = new EAS(easContractAddress);
2692
+ eas.connect(provider);
2693
+ const schemaFilter = schemas.map((s) => s.toLowerCase());
2694
+ const results = [];
2695
+ for (const event of events) {
2696
+ if (!("args" in event) || !Array.isArray(event.args)) continue;
2697
+ const args = event.args;
2698
+ const uid = args?.[2];
2699
+ const schemaUid = args?.[3];
2700
+ if (!uid || !schemaUid) continue;
2701
+ if (!schemaFilter.includes(schemaUid.toLowerCase())) continue;
2702
+ const attestation = await eas.getAttestation(uid);
2703
+ if (!attestation || !attestation.uid) continue;
2704
+ let data = {};
2705
+ const rawData = attestation.data;
2706
+ if (rawData && rawData !== "0x") {
2707
+ try {
2708
+ data = decodeAttestationData(
2709
+ "string subject, string controller, string method",
2710
+ rawData
2711
+ );
2712
+ } catch {
2713
+ try {
2714
+ data = decodeAttestationData(
2715
+ "string subject, string keyId, string publicKeyJwk, string[] keyPurpose, string[] proofs, uint256 issuedAt, uint256 effectiveAt, uint256 expiresAt",
2716
+ rawData
2717
+ );
2718
+ } catch {
2719
+ }
2720
+ }
2721
+ }
2722
+ const toBigIntSafe = (value) => {
2723
+ if (typeof value === "bigint") return value;
2724
+ if (typeof value === "number") return BigInt(value);
2725
+ if (typeof value === "string" && value.length > 0) return BigInt(value);
2726
+ return 0n;
2727
+ };
2728
+ results.push({
2729
+ uid: attestation.uid,
2730
+ schema: attestation.schema,
2731
+ attester: attestation.attester,
2732
+ recipient: attestation.recipient,
2733
+ revocable: Boolean(attestation.revocable),
2734
+ revocationTime: toBigIntSafe(attestation.revocationTime),
2735
+ expirationTime: toBigIntSafe(attestation.expirationTime),
2736
+ time: toBigIntSafe(attestation.time),
2737
+ refUID: attestation.refUID,
2738
+ data
2739
+ });
1502
2740
  }
1503
- return {
1504
- ok: false,
1505
- method: "did-json"
1506
- };
2741
+ return results;
2742
+ }
2743
+ async function findKeyBindingWithTransferProof(keyBindingSchemaUid, easContractAddress, provider, subjectAddress, controllerDid, controllerMethod, fromBlock) {
2744
+ const keyBindings = await queryByRecipientAndSchema(
2745
+ easContractAddress,
2746
+ provider,
2747
+ subjectAddress,
2748
+ [keyBindingSchemaUid],
2749
+ fromBlock
2750
+ );
2751
+ const withProof = keyBindings.filter((att) => {
2752
+ if (!controllerMatchesKeyBinding(att, controllerDid, controllerMethod)) return false;
2753
+ const proofs = att.data?.proofs;
2754
+ if (Array.isArray(proofs)) {
2755
+ return proofs.some((p) => typeof p === "string" && /^0x[0-9a-fA-F]{64}$/.test(p));
2756
+ }
2757
+ return typeof att.data?.proofTxHash === "string";
2758
+ }).sort((a, b) => Number(b.time - a.time));
2759
+ return withProof[0] ?? null;
1507
2760
  }
1508
2761
 
1509
2762
  // src/reputation/proof/tx-interaction.ts
@@ -1613,6 +2866,42 @@ function createX402OfferProof(offer) {
1613
2866
  };
1614
2867
  }
1615
2868
 
2869
+ // src/reputation/proof/x402-verify.ts
2870
+ async function verifyX402Artifact(artifact, options) {
2871
+ if (!artifact || typeof artifact !== "object") {
2872
+ return {
2873
+ valid: false,
2874
+ error: { code: "INVALID_ARTIFACT", message: "Artifact must be a non-null object" }
2875
+ };
2876
+ }
2877
+ const format = artifact.format;
2878
+ switch (format) {
2879
+ case "jws": {
2880
+ const jwsArtifact = artifact;
2881
+ const jwsOptions = options.resolveOptions ? { resolveOptions: options.resolveOptions } : void 0;
2882
+ if (options.artifactType === "offer") {
2883
+ return verifyX402JwsOffer(jwsArtifact, jwsOptions);
2884
+ }
2885
+ return verifyX402JwsReceipt(jwsArtifact, jwsOptions);
2886
+ }
2887
+ case "eip712": {
2888
+ const eip712Artifact = artifact;
2889
+ if (options.artifactType === "offer") {
2890
+ return verifyX402Eip712Offer(eip712Artifact);
2891
+ }
2892
+ return verifyX402Eip712Receipt(eip712Artifact);
2893
+ }
2894
+ default:
2895
+ return {
2896
+ valid: false,
2897
+ error: {
2898
+ code: "UNSUPPORTED_FORMAT",
2899
+ message: `Unsupported x402 artifact format: "${format}"`
2900
+ }
2901
+ };
2902
+ }
2903
+ }
2904
+
1616
2905
  // src/reputation/proof/evidence-pointer.ts
1617
2906
  function createEvidencePointerProof(url) {
1618
2907
  if (!url || typeof url !== "string") {
@@ -1626,63 +2915,12 @@ function createEvidencePointerProof(url) {
1626
2915
  issuedAt: Math.floor(Date.now() / 1e3)
1627
2916
  };
1628
2917
  }
1629
- async function verifyDnsTxtControllerDid(domain, expectedControllerDid, options = {}) {
1630
- if (!domain || typeof domain !== "string") {
1631
- throw new OmaTrustError("INVALID_INPUT", "domain must be a non-empty string", { domain });
1632
- }
1633
- const expected = normalizeDid(expectedControllerDid);
1634
- const prefix = options.recordPrefix ?? "_controllers";
1635
- const host = `${prefix}.${domain.toLowerCase().replace(/\.$/, "")}`;
1636
- let records;
1637
- try {
1638
- records = await (options.resolveTxt ?? resolveTxt)(host);
1639
- } catch (err) {
1640
- throw new OmaTrustError("NETWORK_ERROR", "Failed to resolve DNS TXT records", { domain, err });
1641
- }
1642
- for (const recordParts of records) {
1643
- const record = recordParts.join("");
1644
- const parsed = parseDnsTxtRecord(record);
1645
- if (parsed.version === "1" && parsed.controller && normalizeDid(parsed.controller) === expected) {
1646
- return { valid: true, record };
1647
- }
1648
- }
1649
- return { valid: false, reason: "No TXT record matched expected controller DID" };
1650
- }
1651
-
1652
- // src/reputation/proof/dns-txt-shared.ts
1653
- async function verifyDnsTxtControllerDid2(domain, expectedControllerDid, options = {}) {
1654
- if (!domain || typeof domain !== "string") {
1655
- throw new OmaTrustError("INVALID_INPUT", "domain must be a non-empty string", { domain });
1656
- }
1657
- if (!options.resolveTxt) {
1658
- throw new OmaTrustError("NETWORK_ERROR", "No DNS TXT resolver was provided", { domain });
1659
- }
1660
- const expected = normalizeDid(expectedControllerDid);
1661
- const prefix = options.recordPrefix ?? "_controllers";
1662
- const host = `${prefix}.${domain.toLowerCase().replace(/\.$/, "")}`;
1663
- let records;
1664
- try {
1665
- records = await options.resolveTxt(host);
1666
- } catch (err) {
1667
- throw new OmaTrustError("NETWORK_ERROR", "Failed to resolve DNS TXT records", { domain, err });
1668
- }
1669
- for (const recordParts of records) {
1670
- const record = recordParts.join("");
1671
- const parsed = parseDnsTxtRecord(record);
1672
- if (parsed.version === "1" && parsed.controller && normalizeDid(parsed.controller) === expected) {
1673
- return { valid: true, record };
1674
- }
1675
- }
1676
- return { valid: false, reason: "No TXT record matched expected controller DID" };
2918
+ function verifyDnsTxtControllerDid2(domain, expectedControllerDid, options = {}) {
2919
+ return verifyDnsTxtControllerDid(domain, expectedControllerDid, {
2920
+ ...options,
2921
+ resolveTxt: options.resolveTxt ?? resolveTxt
2922
+ });
1677
2923
  }
1678
-
1679
- // src/reputation/proof/subject-ownership.ts
1680
- var EIP1967_ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
1681
- var OWNERSHIP_PATTERNS = [
1682
- { method: "owner", signature: "function owner() view returns (address)" },
1683
- { method: "admin", signature: "function admin() view returns (address)" },
1684
- { method: "getOwner", signature: "function getOwner() view returns (address)" }
1685
- ];
1686
2924
  function assertConnectedWalletDid(input) {
1687
2925
  const normalized = normalizeDid(input);
1688
2926
  if (extractDidMethod(normalized) !== "pkh") {
@@ -1695,43 +2933,6 @@ function assertConnectedWalletDid(input) {
1695
2933
  function normalizeSubjectDid(input) {
1696
2934
  return normalizeDid(input);
1697
2935
  }
1698
- async function readAddressFromContract(provider, contractAddress, signature, method) {
1699
- try {
1700
- const iface = new Interface([signature]);
1701
- const data = iface.encodeFunctionData(method, []);
1702
- const result = await provider.call({ to: contractAddress, data });
1703
- const [value] = iface.decodeFunctionResult(method, result);
1704
- if (typeof value === "string" && isAddress(value) && value !== ZeroAddress) {
1705
- return getAddress(value);
1706
- }
1707
- } catch {
1708
- }
1709
- return null;
1710
- }
1711
- async function discoverControllingWallet(provider, contractAddress, chainId) {
1712
- for (const pattern of OWNERSHIP_PATTERNS) {
1713
- const address = await readAddressFromContract(
1714
- provider,
1715
- contractAddress,
1716
- pattern.signature,
1717
- pattern.method
1718
- );
1719
- if (address) {
1720
- return buildEvmDidPkh(chainId, address);
1721
- }
1722
- }
1723
- try {
1724
- const adminValue = await provider.getStorage(contractAddress, EIP1967_ADMIN_SLOT);
1725
- if (adminValue && adminValue !== "0x" && adminValue !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
1726
- const adminAddress = getAddress(`0x${adminValue.slice(-40)}`);
1727
- if (adminAddress !== ZeroAddress) {
1728
- return buildEvmDidPkh(chainId, adminAddress);
1729
- }
1730
- }
1731
- } catch {
1732
- }
1733
- return null;
1734
- }
1735
2936
  async function verifyDidWebOwnership(params) {
1736
2937
  const subjectDid = normalizeSubjectDid(params.subjectDid);
1737
2938
  const connectedWalletDid = assertConnectedWalletDid(params.connectedWalletDid);
@@ -1743,7 +2944,7 @@ async function verifyDidWebOwnership(params) {
1743
2944
  }
1744
2945
  let dnsReason;
1745
2946
  try {
1746
- const dnsResult = await verifyDnsTxtControllerDid2(domain, connectedWalletDid, {
2947
+ const dnsResult = await verifyDnsTxtControllerDid(domain, connectedWalletDid, {
1747
2948
  resolveTxt: params.resolveTxt,
1748
2949
  recordPrefix: params.recordPrefix
1749
2950
  });
@@ -1829,7 +3030,7 @@ async function verifyDidPkhOwnership(params) {
1829
3030
  connectedWalletDid
1830
3031
  };
1831
3032
  }
1832
- const controllingWalletDid = await discoverControllingWallet(params.provider, subjectAddress, chainId);
3033
+ const controllingWalletDid = await discoverControllingWalletDid(params.provider, subjectAddress, chainId);
1833
3034
  if (params.txHash) {
1834
3035
  if (!controllingWalletDid) {
1835
3036
  return {
@@ -1912,7 +3113,7 @@ async function verifyDidPkhOwnership(params) {
1912
3113
  };
1913
3114
  }
1914
3115
  for (const pattern of OWNERSHIP_PATTERNS) {
1915
- const ownerAddress = await readAddressFromContract(
3116
+ const ownerAddress = await readOwnerFromContract(
1916
3117
  params.provider,
1917
3118
  subjectAddress,
1918
3119
  pattern.signature,
@@ -1986,7 +3187,301 @@ async function verifySubjectOwnership(params) {
1986
3187
  subjectDid
1987
3188
  });
1988
3189
  }
3190
+ function extractEip712Signer(proof) {
3191
+ const { domain, message, signature } = proof.proofObject;
3192
+ const typedData = {
3193
+ domain,
3194
+ types: {
3195
+ OmaTrustProof: [
3196
+ { name: "signer", type: "address" },
3197
+ { name: "authorizedEntity", type: "string" },
3198
+ { name: "signingPurpose", type: "string" },
3199
+ { name: "creationTimestamp", type: "uint256" },
3200
+ { name: "expirationTimestamp", type: "uint256" },
3201
+ { name: "randomValue", type: "bytes32" },
3202
+ { name: "statement", type: "string" }
3203
+ ]
3204
+ },
3205
+ message
3206
+ };
3207
+ try {
3208
+ const result = verifyEip712Signature(typedData, signature);
3209
+ return result.valid && result.signer ? result.signer : null;
3210
+ } catch (err) {
3211
+ console.warn("[omatrust] EIP-712 signer extraction failed:", err);
3212
+ return null;
3213
+ }
3214
+ }
3215
+ function extractJwsHeaderJwk(proof) {
3216
+ const jws = proof.proofObject;
3217
+ if (typeof jws !== "string") return null;
3218
+ const parts = jws.split(".");
3219
+ if (parts.length !== 3) return null;
3220
+ try {
3221
+ const headerB64 = parts[0].replace(/-/g, "+").replace(/_/g, "/");
3222
+ const padded = headerB64.padEnd(
3223
+ headerB64.length + (4 - headerB64.length % 4) % 4,
3224
+ "="
3225
+ );
3226
+ let headerJson;
3227
+ if (typeof atob === "function") {
3228
+ headerJson = decodeURIComponent(
3229
+ Array.from(atob(padded)).map((char) => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`).join("")
3230
+ );
3231
+ } else {
3232
+ headerJson = Buffer.from(padded, "base64").toString("utf8");
3233
+ }
3234
+ const header = JSON.parse(headerJson);
3235
+ return header.jwk ?? null;
3236
+ } catch {
3237
+ return null;
3238
+ }
3239
+ }
3240
+ function extractJwsPayload(proof) {
3241
+ const jws = proof.proofObject;
3242
+ if (typeof jws !== "string") return null;
3243
+ const parts = jws.split(".");
3244
+ if (parts.length !== 3) return null;
3245
+ try {
3246
+ const payloadB64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
3247
+ const padded = payloadB64.padEnd(
3248
+ payloadB64.length + (4 - payloadB64.length % 4) % 4,
3249
+ "="
3250
+ );
3251
+ let payloadJson;
3252
+ if (typeof atob === "function") {
3253
+ payloadJson = decodeURIComponent(
3254
+ Array.from(atob(padded)).map((char) => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`).join("")
3255
+ );
3256
+ } else {
3257
+ payloadJson = Buffer.from(padded, "base64").toString("utf8");
3258
+ }
3259
+ return JSON.parse(payloadJson);
3260
+ } catch {
3261
+ return null;
3262
+ }
3263
+ }
3264
+ function signerMatchesDid(signerAddress, did) {
3265
+ try {
3266
+ const didAddress = extractAddressFromDid(did);
3267
+ return getAddress(signerAddress).toLowerCase() === getAddress(didAddress).toLowerCase();
3268
+ } catch {
3269
+ return false;
3270
+ }
3271
+ }
3272
+ function jwkMatchesDid(jwk, did) {
3273
+ const method = extractDidMethod(did);
3274
+ if (method === "jwk") {
3275
+ try {
3276
+ const didJwk = didJwkToJwk(did);
3277
+ return publicJwkEquals(jwk, didJwk);
3278
+ } catch {
3279
+ return false;
3280
+ }
3281
+ }
3282
+ return false;
3283
+ }
3284
+ function proofSignerMatchesDid(proof, did) {
3285
+ switch (proof.proofType) {
3286
+ case "pop-eip712": {
3287
+ const signer = extractEip712Signer(proof);
3288
+ if (!signer) return false;
3289
+ return signerMatchesDid(signer, did);
3290
+ }
3291
+ case "pop-jws": {
3292
+ const jwsProof = proof;
3293
+ const jwk = extractJwsHeaderJwk(jwsProof);
3294
+ if (jwk && jwkMatchesDid(jwk, did)) return true;
3295
+ const payload = extractJwsPayload(jwsProof);
3296
+ if (payload && typeof payload.iss === "string") {
3297
+ if (payload.iss === did) return true;
3298
+ }
3299
+ return false;
3300
+ }
3301
+ case "tx-encoded-value":
3302
+ case "tx-interaction":
3303
+ return false;
3304
+ case "evidence-pointer":
3305
+ return false;
3306
+ default:
3307
+ return false;
3308
+ }
3309
+ }
3310
+ function proofAuthorizedEntityMatchesDid(proof, did) {
3311
+ switch (proof.proofType) {
3312
+ case "pop-eip712": {
3313
+ const eip712 = proof;
3314
+ const authorizedEntity = eip712.proofObject.message.authorizedEntity;
3315
+ return typeof authorizedEntity === "string" && authorizedEntity === did;
3316
+ }
3317
+ case "pop-jws": {
3318
+ const payload = extractJwsPayload(proof);
3319
+ if (!payload) return false;
3320
+ return typeof payload.aud === "string" && payload.aud === did;
3321
+ }
3322
+ default:
3323
+ return false;
3324
+ }
3325
+ }
3326
+ function verifyLinkedIdentifierProofs(data) {
3327
+ if (!data.subject || !data.linkedId) {
3328
+ return {
3329
+ valid: false,
3330
+ checks: [],
3331
+ reasons: ["subject and linkedId are required"]
3332
+ };
3333
+ }
3334
+ if (!Array.isArray(data.proofs) || data.proofs.length === 0) {
3335
+ return {
3336
+ valid: false,
3337
+ checks: [],
3338
+ reasons: ["At least one proof is required"]
3339
+ };
3340
+ }
3341
+ const checks = [];
3342
+ let subjectProved = false;
3343
+ let linkedIdProved = false;
3344
+ for (let i = 0; i < data.proofs.length; i++) {
3345
+ const proof = data.proofs[i];
3346
+ if (proofSignerMatchesDid(proof, data.subject)) {
3347
+ checks.push({
3348
+ proofIndex: i,
3349
+ proofType: proof.proofType,
3350
+ checkType: "signer-is-subject",
3351
+ valid: true
3352
+ });
3353
+ subjectProved = true;
3354
+ if (!proofAuthorizedEntityMatchesDid(proof, data.linkedId)) {
3355
+ checks.push({
3356
+ proofIndex: i,
3357
+ proofType: proof.proofType,
3358
+ checkType: "signer-is-subject",
3359
+ valid: false,
3360
+ reason: "Proof from subject does not authorize linkedId (aud mismatch)"
3361
+ });
3362
+ }
3363
+ }
3364
+ if (proofSignerMatchesDid(proof, data.linkedId)) {
3365
+ checks.push({
3366
+ proofIndex: i,
3367
+ proofType: proof.proofType,
3368
+ checkType: "signer-is-linkedId",
3369
+ valid: true
3370
+ });
3371
+ linkedIdProved = true;
3372
+ if (!proofAuthorizedEntityMatchesDid(proof, data.subject)) {
3373
+ checks.push({
3374
+ proofIndex: i,
3375
+ proofType: proof.proofType,
3376
+ checkType: "signer-is-linkedId",
3377
+ valid: false,
3378
+ reason: "Proof from linkedId does not authorize subject (aud mismatch)"
3379
+ });
3380
+ }
3381
+ }
3382
+ if (proof.proofType === "evidence-pointer") {
3383
+ checks.push({
3384
+ proofIndex: i,
3385
+ proofType: proof.proofType,
3386
+ checkType: "signer-is-subject",
3387
+ valid: true,
3388
+ reason: "Evidence pointer accepted (requires URL fetch for full verification)"
3389
+ });
3390
+ subjectProved = true;
3391
+ }
3392
+ }
3393
+ const reasons = [];
3394
+ if (!subjectProved) {
3395
+ reasons.push("No proof demonstrates control by subject");
3396
+ }
3397
+ if (!linkedIdProved) {
3398
+ reasons.push("No proof demonstrates control by linkedId");
3399
+ }
3400
+ return {
3401
+ valid: reasons.length === 0,
3402
+ checks,
3403
+ reasons
3404
+ };
3405
+ }
3406
+ function verifyKeyBindingProofs(data) {
3407
+ if (!data.subject || !data.keyId) {
3408
+ return {
3409
+ valid: false,
3410
+ checks: [],
3411
+ reasons: ["subject and keyId are required"]
3412
+ };
3413
+ }
3414
+ if (!Array.isArray(data.proofs) || data.proofs.length === 0) {
3415
+ return {
3416
+ valid: false,
3417
+ checks: [],
3418
+ reasons: ["At least one proof is required"]
3419
+ };
3420
+ }
3421
+ const checks = [];
3422
+ let subjectAuthorizedKey = false;
3423
+ for (let i = 0; i < data.proofs.length; i++) {
3424
+ const proof = data.proofs[i];
3425
+ if (proofSignerMatchesDid(proof, data.subject)) {
3426
+ const authorizesKey = proofAuthorizedEntityMatchesDid(proof, data.keyId);
3427
+ checks.push({
3428
+ proofIndex: i,
3429
+ proofType: proof.proofType,
3430
+ checkType: "signer-is-subject-for-key",
3431
+ valid: authorizesKey,
3432
+ reason: authorizesKey ? void 0 : "Proof signed by subject but does not authorize the keyId"
3433
+ });
3434
+ if (authorizesKey) {
3435
+ subjectAuthorizedKey = true;
3436
+ }
3437
+ }
3438
+ if (proofSignerMatchesDid(proof, data.keyId)) {
3439
+ checks.push({
3440
+ proofIndex: i,
3441
+ proofType: proof.proofType,
3442
+ checkType: "signer-is-keyId",
3443
+ valid: true,
3444
+ reason: "Key proved possession (supplementary, not sufficient alone)"
3445
+ });
3446
+ }
3447
+ if (proof.proofType === "evidence-pointer") {
3448
+ checks.push({
3449
+ proofIndex: i,
3450
+ proofType: proof.proofType,
3451
+ checkType: "signer-is-subject-for-key",
3452
+ valid: true,
3453
+ reason: "Evidence pointer accepted (requires URL fetch for full verification)"
3454
+ });
3455
+ subjectAuthorizedKey = true;
3456
+ }
3457
+ }
3458
+ if (data.publicKeyJwk && extractDidMethod(data.keyId) === "jwk") {
3459
+ try {
3460
+ const keyIdJwk = didJwkToJwk(data.keyId);
3461
+ const jwkConsistent = publicJwkEquals(data.publicKeyJwk, keyIdJwk);
3462
+ if (!jwkConsistent) {
3463
+ return {
3464
+ valid: false,
3465
+ checks,
3466
+ reasons: ["publicKeyJwk does not match the key material in keyId (did:jwk)"]
3467
+ };
3468
+ }
3469
+ } catch {
3470
+ }
3471
+ }
3472
+ const reasons = [];
3473
+ if (!subjectAuthorizedKey) {
3474
+ reasons.push(
3475
+ "No proof demonstrates that subject authorized the key binding"
3476
+ );
3477
+ }
3478
+ return {
3479
+ valid: reasons.length === 0,
3480
+ checks,
3481
+ reasons
3482
+ };
3483
+ }
1989
3484
 
1990
- export { buildDelegatedAttestationTypedData, buildDelegatedTypedDataFromEncoded, buildDnsTxtRecord, buildEip712Domain, calculateAverageUserReviewRating, calculateTransferAmount, calculateTransferAmountFromAddresses, callControllerWitness, constructSeed, createEvidencePointerProof, createPopEip712Proof, createPopJwsProof, createTxEncodedValueProof, createTxInteractionProof, createX402OfferProof, createX402ReceiptProof, decodeAttestationData, deduplicateReviews, encodeAttestationData, extractAddressesFromDidDocument, extractExpirationTime, fetchDidDocument, formatSchemaUid, formatTransferAmount, getAttestation, getAttestationsByAttester, getAttestationsForDid, getChainConstants, getExplorerAddressUrl, getExplorerTxUrl, getLatestAttestations, getMajorVersion, getOmaTrustProofEip712Types, getSchemaDetails, getSupportedChainIds, hashSeed, isChainSupported, listAttestations, normalizeSchema, parseDnsTxtRecord, prepareDelegatedAttestation, revokeAttestation, schemaToString, splitSignature, submitAttestation, submitDelegatedAttestation, validateAttestationData, verifyAttestation, verifyDidDocumentControllerDid, verifyDidJsonControllerDid, verifyDidPkhOwnership, verifyDidWebOwnership, verifyDnsTxtControllerDid, verifyEip712Signature, verifyProof, verifySchemaExists, verifySubjectOwnership };
3485
+ export { EIP1967_ADMIN_SLOT, OWNERSHIP_PATTERNS, buildDelegatedAttestationTypedData, buildDelegatedTypedDataFromEncoded, buildDnsTxtRecord, buildEip712Domain, calculateAverageUserReviewRating, calculateTransferAmount, calculateTransferAmountFromAddresses, callControllerWitness, constructSeed, createEvidencePointerProof, createPopEip712Proof, createPopJwsProof, createTxEncodedValueProof, createTxInteractionProof, createX402OfferProof, createX402ReceiptProof, decodeAttestationData, deduplicateReviews, discoverContractOwner, discoverControllingWalletDid, encodeAttestationData, extractEvmAddressesFromDidDocument, extractExpirationTime, extractJwksFromDidDocument, fetchDidDocument, formatSchemaUid, formatTransferAmount, getAttestation, getAttestationsByAttester, getAttestationsForDid, getChainConstants, getControllerAuthorization, getExplorerAddressUrl, getExplorerTxUrl, getLatestAttestations, getMajorVersion, getOmaTrustProofEip712Types, getSchemaDetails, getSupportedChainIds, hashSeed, isChainSupported, listAttestations, normalizeSchema, parseDnsTxtRecord, prepareDelegatedAttestation, readOwnerFromContract, requestControllerWitness, revokeAttestation, schemaToString, splitSignature, submitAttestation, submitDelegatedAttestation, validateAttestationData, verifyAttestation, verifyDidDocumentControllerDid, verifyDidJsonControllerDid, verifyDidPkhOwnership, verifyDidWebOwnership, verifyDnsTxtControllerDid2 as verifyDnsTxtControllerDid, verifyEip712Signature, verifyKeyBindingProofs, verifyLinkedIdentifierProofs, verifyProof, verifySchemaExists, verifySubjectOwnership, verifyTransferProof, verifyX402Artifact, verifyX402Eip712Artifact, verifyX402Eip712Offer, verifyX402Eip712Receipt, verifyX402JwsArtifact, verifyX402JwsOffer, verifyX402JwsReceipt };
1991
3486
  //# sourceMappingURL=index.js.map
1992
3487
  //# sourceMappingURL=index.js.map