@oma3/omatrust 0.1.0-alpha.1 → 0.1.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -7
- package/dist/identity/index.cjs +1 -1
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.js +1 -1
- package/dist/identity/index.js.map +1 -1
- package/dist/index-B9KW02US.d.cts +119 -0
- package/dist/index-DXrwBex9.d.ts +119 -0
- package/dist/index.cjs +656 -91
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +657 -92
- package/dist/index.js.map +1 -1
- package/dist/reputation/index.browser.cjs +2133 -0
- package/dist/reputation/index.browser.cjs.map +1 -0
- package/dist/reputation/index.browser.d.cts +14 -0
- package/dist/reputation/index.browser.d.ts +14 -0
- package/dist/reputation/index.browser.js +2071 -0
- package/dist/reputation/index.browser.js.map +1 -0
- package/dist/reputation/index.cjs +675 -90
- package/dist/reputation/index.cjs.map +1 -1
- package/dist/reputation/index.d.cts +2 -1
- package/dist/reputation/index.d.ts +2 -1
- package/dist/reputation/index.js +669 -92
- package/dist/reputation/index.js.map +1 -1
- package/dist/subject-ownership-CXvzEjpH.d.cts +434 -0
- package/dist/subject-ownership-CXvzEjpH.d.ts +434 -0
- package/dist/widgets/index.cjs +195 -0
- package/dist/widgets/index.cjs.map +1 -0
- package/dist/widgets/index.d.cts +134 -0
- package/dist/widgets/index.d.ts +134 -0
- package/dist/widgets/index.js +185 -0
- package/dist/widgets/index.js.map +1 -0
- package/package.json +33 -6
- package/dist/index-ChbJxwOA.d.cts +0 -415
- package/dist/index-ChbJxwOA.d.ts +0 -415
package/dist/reputation/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SchemaEncoder, EAS } from '@ethereum-attestation-service/eas-sdk';
|
|
2
|
-
import { ZeroAddress, Signature,
|
|
2
|
+
import { ZeroAddress, Signature, toUtf8Bytes, sha256, keccak256, formatUnits, getAddress, isAddress, verifyTypedData, hexlify, randomBytes, Contract, Interface } from 'ethers';
|
|
3
3
|
import canonicalize from 'canonicalize';
|
|
4
4
|
import { resolveTxt } from 'dns/promises';
|
|
5
5
|
|
|
@@ -52,6 +52,13 @@ function encodeAttestationData(schema, data) {
|
|
|
52
52
|
if (!data || typeof data !== "object") {
|
|
53
53
|
throw new OmaTrustError("INVALID_INPUT", "data must be an object");
|
|
54
54
|
}
|
|
55
|
+
const validationErrors = validateAttestationData(schema, data);
|
|
56
|
+
if (validationErrors.length > 0) {
|
|
57
|
+
const summary = validationErrors.map((error) => `Field "${error.schemaFieldName}" (${error.expectedType}) got ${error.providedType}`).join("; ");
|
|
58
|
+
throw new OmaTrustError("INVALID_INPUT", `Attestation data validation failed: ${summary}`, {
|
|
59
|
+
errors: validationErrors
|
|
60
|
+
});
|
|
61
|
+
}
|
|
55
62
|
const fields = normalizeSchema(schema);
|
|
56
63
|
const schemaString = schemaToString(fields);
|
|
57
64
|
const encoder = new SchemaEncoder(schemaString);
|
|
@@ -64,6 +71,99 @@ function encodeAttestationData(schema, data) {
|
|
|
64
71
|
);
|
|
65
72
|
return encoded;
|
|
66
73
|
}
|
|
74
|
+
function getActualType(value) {
|
|
75
|
+
if (value === null) {
|
|
76
|
+
return "null";
|
|
77
|
+
}
|
|
78
|
+
if (value === void 0) {
|
|
79
|
+
return "undefined";
|
|
80
|
+
}
|
|
81
|
+
if (Array.isArray(value)) {
|
|
82
|
+
return "array";
|
|
83
|
+
}
|
|
84
|
+
if (typeof value === "number") {
|
|
85
|
+
return Number.isFinite(value) ? "number" : "non-finite-number";
|
|
86
|
+
}
|
|
87
|
+
return typeof value;
|
|
88
|
+
}
|
|
89
|
+
function isNumericValue(value, allowNegative) {
|
|
90
|
+
if (typeof value === "bigint") {
|
|
91
|
+
return allowNegative || value >= 0n;
|
|
92
|
+
}
|
|
93
|
+
if (typeof value === "number") {
|
|
94
|
+
if (!Number.isFinite(value) || !Number.isInteger(value)) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return allowNegative || value >= 0;
|
|
98
|
+
}
|
|
99
|
+
if (typeof value === "string") {
|
|
100
|
+
if (value.length === 0) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const pattern = allowNegative ? /^-?\d+$/ : /^\d+$/;
|
|
104
|
+
return pattern.test(value);
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
function isHex(value) {
|
|
109
|
+
return typeof value === "string" && /^0x[0-9a-fA-F]*$/.test(value);
|
|
110
|
+
}
|
|
111
|
+
function validateFieldValue(type, value) {
|
|
112
|
+
const normalizedType = type.trim().toLowerCase();
|
|
113
|
+
const bytesNMatch = normalizedType.match(/^bytes([1-9]|[12]\d|3[0-2])$/);
|
|
114
|
+
if (/^uint\d*$/.test(normalizedType)) {
|
|
115
|
+
return isNumericValue(value, false);
|
|
116
|
+
}
|
|
117
|
+
if (/^int\d*$/.test(normalizedType)) {
|
|
118
|
+
return isNumericValue(value, true);
|
|
119
|
+
}
|
|
120
|
+
if (normalizedType === "string") {
|
|
121
|
+
return typeof value === "string";
|
|
122
|
+
}
|
|
123
|
+
if (normalizedType === "string[]") {
|
|
124
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
125
|
+
}
|
|
126
|
+
if (normalizedType === "bool") {
|
|
127
|
+
return typeof value === "boolean";
|
|
128
|
+
}
|
|
129
|
+
if (normalizedType === "address") {
|
|
130
|
+
return typeof value === "string" && isAddress(value);
|
|
131
|
+
}
|
|
132
|
+
if (normalizedType === "bytes") {
|
|
133
|
+
return isHex(value) && (value.length - 2) % 2 === 0;
|
|
134
|
+
}
|
|
135
|
+
if (bytesNMatch) {
|
|
136
|
+
const expectedBytes = Number(bytesNMatch[1]);
|
|
137
|
+
return isHex(value) && value.length === 2 + expectedBytes * 2;
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
function validateAttestationData(schema, data) {
|
|
142
|
+
if (!data || typeof data !== "object") {
|
|
143
|
+
return [{
|
|
144
|
+
schemaFieldName: "data",
|
|
145
|
+
expectedType: "object",
|
|
146
|
+
providedType: getActualType(data),
|
|
147
|
+
providedValue: data
|
|
148
|
+
}];
|
|
149
|
+
}
|
|
150
|
+
const fields = normalizeSchema(schema);
|
|
151
|
+
const errors = [];
|
|
152
|
+
for (const field of fields) {
|
|
153
|
+
const value = data[field.name];
|
|
154
|
+
const isValid = validateFieldValue(field.type, value);
|
|
155
|
+
if (isValid) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
errors.push({
|
|
159
|
+
schemaFieldName: field.name,
|
|
160
|
+
expectedType: field.type,
|
|
161
|
+
providedType: getActualType(value),
|
|
162
|
+
providedValue: value
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return errors;
|
|
166
|
+
}
|
|
67
167
|
function decodeAttestationData(schema, encodedData) {
|
|
68
168
|
if (typeof encodedData !== "string" || !encodedData.startsWith("0x")) {
|
|
69
169
|
throw new OmaTrustError("INVALID_INPUT", "encodedData must be a hex string");
|
|
@@ -84,22 +184,11 @@ function decodeAttestationData(schema, encodedData) {
|
|
|
84
184
|
return result;
|
|
85
185
|
}
|
|
86
186
|
function extractExpirationTime(data) {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
if (typeof value === "bigint") {
|
|
94
|
-
return value;
|
|
95
|
-
}
|
|
96
|
-
if (typeof value === "number") {
|
|
97
|
-
return value;
|
|
98
|
-
}
|
|
99
|
-
if (typeof value === "string" && /^\d+$/.test(value)) {
|
|
100
|
-
return BigInt(value);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
187
|
+
const value = data["expiresAt"];
|
|
188
|
+
if (value === void 0 || value === null) return void 0;
|
|
189
|
+
if (typeof value === "bigint") return value;
|
|
190
|
+
if (typeof value === "number") return value;
|
|
191
|
+
if (typeof value === "string" && /^\d+$/.test(value)) return BigInt(value);
|
|
103
192
|
return void 0;
|
|
104
193
|
}
|
|
105
194
|
|
|
@@ -139,7 +228,7 @@ function extractDidMethod(did) {
|
|
|
139
228
|
}
|
|
140
229
|
function normalizeDomain(domain) {
|
|
141
230
|
assertString(domain, "domain", "INVALID_DID");
|
|
142
|
-
return domain.trim().toLowerCase().replace(/\.$/, "");
|
|
231
|
+
return domain.trim().toLowerCase().replace(/\.$/, "").replace(/^www\./, "");
|
|
143
232
|
}
|
|
144
233
|
function normalizeDidWeb(input) {
|
|
145
234
|
assertString(input, "input", "INVALID_DID");
|
|
@@ -258,6 +347,26 @@ function parseDidPkh(did) {
|
|
|
258
347
|
}
|
|
259
348
|
return { namespace, chainId, address };
|
|
260
349
|
}
|
|
350
|
+
function getChainIdFromDidPkh(did) {
|
|
351
|
+
return parseDidPkh(did)?.chainId ?? null;
|
|
352
|
+
}
|
|
353
|
+
function getAddressFromDidPkh(did) {
|
|
354
|
+
return parseDidPkh(did)?.address ?? null;
|
|
355
|
+
}
|
|
356
|
+
function getNamespaceFromDidPkh(did) {
|
|
357
|
+
return parseDidPkh(did)?.namespace ?? null;
|
|
358
|
+
}
|
|
359
|
+
function isEvmDidPkh(did) {
|
|
360
|
+
return getNamespaceFromDidPkh(did) === "eip155";
|
|
361
|
+
}
|
|
362
|
+
function getDomainFromDidWeb(did) {
|
|
363
|
+
if (!did.startsWith("did:web:")) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
const identifier = did.slice("did:web:".length);
|
|
367
|
+
const [domain] = identifier.split("/");
|
|
368
|
+
return domain || null;
|
|
369
|
+
}
|
|
261
370
|
function extractAddressFromDid(identifier) {
|
|
262
371
|
assertString(identifier, "identifier", "INVALID_DID");
|
|
263
372
|
if (identifier.startsWith("did:pkh:")) {
|
|
@@ -324,6 +433,53 @@ function resolveRecipientAddress(data) {
|
|
|
324
433
|
return ZeroAddress;
|
|
325
434
|
}
|
|
326
435
|
|
|
436
|
+
// src/reputation/eas-adapter.ts
|
|
437
|
+
function isRecord(value) {
|
|
438
|
+
return Boolean(value) && typeof value === "object";
|
|
439
|
+
}
|
|
440
|
+
function isHex32(value) {
|
|
441
|
+
return typeof value === "string" && /^0x[0-9a-fA-F]{64}$/.test(value);
|
|
442
|
+
}
|
|
443
|
+
function getEasTransactionReceipt(tx) {
|
|
444
|
+
if (!isRecord(tx)) {
|
|
445
|
+
return void 0;
|
|
446
|
+
}
|
|
447
|
+
const candidates = [tx.receipt, tx.tx, tx.transaction];
|
|
448
|
+
for (const candidate of candidates) {
|
|
449
|
+
if (isRecord(candidate)) {
|
|
450
|
+
return candidate;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return void 0;
|
|
454
|
+
}
|
|
455
|
+
function getEasTransactionHash(tx) {
|
|
456
|
+
const receipt = getEasTransactionReceipt(tx);
|
|
457
|
+
if (receipt) {
|
|
458
|
+
const receiptHash = receipt.hash;
|
|
459
|
+
if (isHex32(receiptHash)) {
|
|
460
|
+
return receiptHash;
|
|
461
|
+
}
|
|
462
|
+
const transactionHash = receipt.transactionHash;
|
|
463
|
+
if (isHex32(transactionHash)) {
|
|
464
|
+
return transactionHash;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (isRecord(tx) && isHex32(tx.hash)) {
|
|
468
|
+
return tx.hash;
|
|
469
|
+
}
|
|
470
|
+
return void 0;
|
|
471
|
+
}
|
|
472
|
+
function isEasSchemaNotFoundError(err) {
|
|
473
|
+
if (!isRecord(err)) {
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
const message = err.message;
|
|
477
|
+
if (typeof message !== "string" || message.length === 0) {
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
return /schema not found/i.test(message);
|
|
481
|
+
}
|
|
482
|
+
|
|
327
483
|
// src/reputation/submit.ts
|
|
328
484
|
async function submitAttestation(params) {
|
|
329
485
|
if (!params || typeof params !== "object") {
|
|
@@ -354,25 +510,46 @@ async function submitAttestation(params) {
|
|
|
354
510
|
}
|
|
355
511
|
});
|
|
356
512
|
const uid = await tx.wait();
|
|
357
|
-
const
|
|
358
|
-
const
|
|
513
|
+
const txHash = getEasTransactionHash(tx) ?? ZERO_UID;
|
|
514
|
+
const receipt = getEasTransactionReceipt(tx);
|
|
359
515
|
return {
|
|
360
516
|
uid,
|
|
361
517
|
txHash,
|
|
362
|
-
receipt
|
|
518
|
+
receipt
|
|
363
519
|
};
|
|
364
520
|
} catch (err) {
|
|
365
521
|
throw new OmaTrustError("NETWORK_ERROR", "Failed to submit attestation", { err });
|
|
366
522
|
}
|
|
367
523
|
}
|
|
368
|
-
function
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
);
|
|
524
|
+
async function revokeAttestation(params) {
|
|
525
|
+
if (!params || typeof params !== "object") {
|
|
526
|
+
throw new OmaTrustError("INVALID_INPUT", "params must be provided");
|
|
527
|
+
}
|
|
528
|
+
if (!params.signer) {
|
|
529
|
+
throw new OmaTrustError("INVALID_INPUT", "signer is required");
|
|
530
|
+
}
|
|
531
|
+
const eas = new EAS(params.easContractAddress);
|
|
532
|
+
eas.connect(params.signer);
|
|
533
|
+
try {
|
|
534
|
+
const tx = await eas.revoke({
|
|
535
|
+
schema: params.schemaUid,
|
|
536
|
+
data: {
|
|
537
|
+
uid: params.uid,
|
|
538
|
+
value: toBigIntOrDefault(params.value, 0n)
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
await tx.wait();
|
|
542
|
+
const txHash = getEasTransactionHash(tx) ?? ZERO_UID;
|
|
543
|
+
const receipt = getEasTransactionReceipt(tx);
|
|
544
|
+
return {
|
|
545
|
+
txHash,
|
|
546
|
+
receipt
|
|
547
|
+
};
|
|
548
|
+
} catch (err) {
|
|
549
|
+
throw new OmaTrustError("NETWORK_ERROR", "Failed to revoke attestation", { err });
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
function buildDelegatedTypedData(params) {
|
|
376
553
|
return {
|
|
377
554
|
domain: {
|
|
378
555
|
name: "EAS",
|
|
@@ -397,17 +574,52 @@ function buildDelegatedAttestationTypedData(params) {
|
|
|
397
574
|
message: {
|
|
398
575
|
attester: params.attester,
|
|
399
576
|
schema: params.schemaUid,
|
|
400
|
-
recipient,
|
|
401
|
-
expirationTime:
|
|
577
|
+
recipient: params.recipient,
|
|
578
|
+
expirationTime: toBigIntOrDefault(params.expirationTime, 0n),
|
|
402
579
|
revocable: params.revocable ?? true,
|
|
403
580
|
refUID: params.refUid ?? ZERO_UID,
|
|
404
|
-
data: encodedData,
|
|
581
|
+
data: params.encodedData,
|
|
405
582
|
value: toBigIntOrDefault(params.value, 0n),
|
|
406
583
|
nonce: toBigIntOrDefault(params.nonce, 0n),
|
|
407
584
|
deadline: toBigIntOrDefault(params.deadline, BigInt(Math.floor(Date.now() / 1e3) + 600))
|
|
408
585
|
}
|
|
409
586
|
};
|
|
410
587
|
}
|
|
588
|
+
function buildDelegatedAttestationTypedData(params) {
|
|
589
|
+
const dataWithHash = withAutoSubjectDidHash(params.schema, params.data);
|
|
590
|
+
const encodedData = encodeAttestationData(params.schema, dataWithHash);
|
|
591
|
+
const recipient = resolveRecipientAddress(dataWithHash);
|
|
592
|
+
return buildDelegatedTypedData({
|
|
593
|
+
chainId: params.chainId,
|
|
594
|
+
easContractAddress: params.easContractAddress,
|
|
595
|
+
schemaUid: params.schemaUid,
|
|
596
|
+
encodedData,
|
|
597
|
+
recipient,
|
|
598
|
+
attester: params.attester,
|
|
599
|
+
nonce: params.nonce,
|
|
600
|
+
revocable: params.revocable,
|
|
601
|
+
expirationTime: params.expirationTime ?? extractExpirationTime(dataWithHash),
|
|
602
|
+
refUid: params.refUid,
|
|
603
|
+
value: params.value,
|
|
604
|
+
deadline: params.deadline
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
function buildDelegatedTypedDataFromEncoded(params) {
|
|
608
|
+
return buildDelegatedTypedData({
|
|
609
|
+
chainId: params.chainId,
|
|
610
|
+
easContractAddress: params.easContractAddress,
|
|
611
|
+
schemaUid: params.schemaUid,
|
|
612
|
+
encodedData: params.encodedData,
|
|
613
|
+
recipient: params.recipient,
|
|
614
|
+
attester: params.attester,
|
|
615
|
+
nonce: params.nonce,
|
|
616
|
+
revocable: params.revocable,
|
|
617
|
+
expirationTime: params.expirationTime,
|
|
618
|
+
refUid: params.refUid,
|
|
619
|
+
value: params.value,
|
|
620
|
+
deadline: params.deadline
|
|
621
|
+
});
|
|
622
|
+
}
|
|
411
623
|
function splitSignature(signature) {
|
|
412
624
|
try {
|
|
413
625
|
const parsed = Signature.from(signature);
|
|
@@ -484,7 +696,14 @@ async function submitDelegatedAttestation(params) {
|
|
|
484
696
|
var EAS_EVENT_ABI = [
|
|
485
697
|
"event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID)"
|
|
486
698
|
];
|
|
487
|
-
function
|
|
699
|
+
function parseEventTxHash(event) {
|
|
700
|
+
const txHash = event.transactionHash;
|
|
701
|
+
if (typeof txHash !== "string") {
|
|
702
|
+
return void 0;
|
|
703
|
+
}
|
|
704
|
+
return /^0x[0-9a-fA-F]{64}$/.test(txHash) ? txHash : void 0;
|
|
705
|
+
}
|
|
706
|
+
function parseAttestation(attestation, schema, txHash) {
|
|
488
707
|
const rawData = attestation.data ?? "0x";
|
|
489
708
|
const decoded = schema ? decodeAttestationData(schema, rawData) : {};
|
|
490
709
|
const toBigIntSafe = (value) => {
|
|
@@ -504,6 +723,7 @@ function parseAttestation(attestation, schema) {
|
|
|
504
723
|
schema: attestation.schema,
|
|
505
724
|
attester: attestation.attester,
|
|
506
725
|
recipient: attestation.recipient,
|
|
726
|
+
txHash,
|
|
507
727
|
revocable: Boolean(attestation.revocable),
|
|
508
728
|
revocationTime: toBigIntSafe(attestation.revocationTime),
|
|
509
729
|
expirationTime: toBigIntSafe(attestation.expirationTime),
|
|
@@ -529,21 +749,18 @@ async function getAttestation(params) {
|
|
|
529
749
|
throw new OmaTrustError("NETWORK_ERROR", "Failed to read attestation", { err });
|
|
530
750
|
}
|
|
531
751
|
}
|
|
532
|
-
async function
|
|
533
|
-
const
|
|
534
|
-
const
|
|
535
|
-
const toBlock = params.toBlock ?? await provider.getBlockNumber();
|
|
536
|
-
const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
|
|
537
|
-
const filter = contract.filters.Attested(didToAddress(params.did));
|
|
752
|
+
async function queryAttestationEvents(easContractAddress, provider, fromBlock, toBlock, options) {
|
|
753
|
+
const contract = new Contract(easContractAddress, EAS_EVENT_ABI, provider);
|
|
754
|
+
const filter = contract.filters.Attested(options?.recipient ?? null, options?.attester ?? null);
|
|
538
755
|
let events;
|
|
539
756
|
try {
|
|
540
757
|
events = await contract.queryFilter(filter, fromBlock, toBlock);
|
|
541
758
|
} catch (err) {
|
|
542
759
|
throw new OmaTrustError("NETWORK_ERROR", "Failed to query attestation events", { err });
|
|
543
760
|
}
|
|
544
|
-
const eas = new EAS(
|
|
761
|
+
const eas = new EAS(easContractAddress);
|
|
545
762
|
eas.connect(provider);
|
|
546
|
-
const schemaFilter =
|
|
763
|
+
const schemaFilter = options?.schemas?.map((s) => s.toLowerCase());
|
|
547
764
|
const results = [];
|
|
548
765
|
for (const event of events) {
|
|
549
766
|
if (!("args" in event && Array.isArray(event.args))) {
|
|
@@ -562,11 +779,39 @@ async function getAttestationsForDid(params) {
|
|
|
562
779
|
if (!attestation || !attestation.uid) {
|
|
563
780
|
continue;
|
|
564
781
|
}
|
|
565
|
-
results.push(parseAttestation(attestation));
|
|
782
|
+
results.push(parseAttestation(attestation, void 0, parseEventTxHash(event)));
|
|
566
783
|
}
|
|
567
784
|
results.sort((a, b) => Number(b.time - a.time));
|
|
568
785
|
return results;
|
|
569
786
|
}
|
|
787
|
+
async function getAttestationsForDid(params) {
|
|
788
|
+
const provider = params.provider;
|
|
789
|
+
const toBlock = params.toBlock ?? await provider.getBlockNumber();
|
|
790
|
+
const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
|
|
791
|
+
return queryAttestationEvents(
|
|
792
|
+
params.easContractAddress,
|
|
793
|
+
provider,
|
|
794
|
+
fromBlock,
|
|
795
|
+
toBlock,
|
|
796
|
+
{ recipient: didToAddress(params.did), schemas: params.schemas }
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
async function getAttestationsByAttester(params) {
|
|
800
|
+
const provider = params.provider;
|
|
801
|
+
const toBlock = params.toBlock ?? await provider.getBlockNumber();
|
|
802
|
+
const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
|
|
803
|
+
if (params.limit !== void 0 && params.limit <= 0) {
|
|
804
|
+
return [];
|
|
805
|
+
}
|
|
806
|
+
const results = await queryAttestationEvents(
|
|
807
|
+
params.easContractAddress,
|
|
808
|
+
provider,
|
|
809
|
+
fromBlock,
|
|
810
|
+
toBlock,
|
|
811
|
+
{ attester: params.attester, schemas: params.schemas }
|
|
812
|
+
);
|
|
813
|
+
return params.limit !== void 0 ? results.slice(0, params.limit) : results;
|
|
814
|
+
}
|
|
570
815
|
async function listAttestations(params) {
|
|
571
816
|
const limit = params.limit ?? 20;
|
|
572
817
|
if (limit <= 0) {
|
|
@@ -577,34 +822,15 @@ async function listAttestations(params) {
|
|
|
577
822
|
}
|
|
578
823
|
async function getLatestAttestations(params) {
|
|
579
824
|
const provider = params.provider;
|
|
580
|
-
const
|
|
581
|
-
const
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
if (!("args" in event && Array.isArray(event.args))) {
|
|
590
|
-
continue;
|
|
591
|
-
}
|
|
592
|
-
const args = event.args;
|
|
593
|
-
const uid = args?.[2];
|
|
594
|
-
const schemaUid = args?.[3];
|
|
595
|
-
if (!uid || !schemaUid) {
|
|
596
|
-
continue;
|
|
597
|
-
}
|
|
598
|
-
if (schemaFilter && !schemaFilter.includes(schemaUid.toLowerCase())) {
|
|
599
|
-
continue;
|
|
600
|
-
}
|
|
601
|
-
const attestation = await eas.getAttestation(uid);
|
|
602
|
-
if (!attestation || !attestation.uid) {
|
|
603
|
-
continue;
|
|
604
|
-
}
|
|
605
|
-
results.push(parseAttestation(attestation));
|
|
606
|
-
}
|
|
607
|
-
results.sort((a, b) => Number(b.time - a.time));
|
|
825
|
+
const toBlock = await provider.getBlockNumber();
|
|
826
|
+
const fromBlock = params.fromBlock ?? Math.max(0, toBlock - 5e4);
|
|
827
|
+
const results = await queryAttestationEvents(
|
|
828
|
+
params.easContractAddress,
|
|
829
|
+
provider,
|
|
830
|
+
fromBlock,
|
|
831
|
+
toBlock,
|
|
832
|
+
{ schemas: params.schemas }
|
|
833
|
+
);
|
|
608
834
|
return results.slice(0, params.limit ?? 20);
|
|
609
835
|
}
|
|
610
836
|
function deduplicateReviews(attestations) {
|
|
@@ -866,6 +1092,13 @@ function verifyDidDocumentControllerDid(didDocument, expectedControllerDid) {
|
|
|
866
1092
|
reason: `No matching address found in DID document (expected ${expectedAddress})`
|
|
867
1093
|
};
|
|
868
1094
|
}
|
|
1095
|
+
async function verifyDidJsonControllerDid(domain, expectedControllerDid, options = {}) {
|
|
1096
|
+
if (!domain || typeof domain !== "string") {
|
|
1097
|
+
throw new OmaTrustError("INVALID_INPUT", "domain must be a non-empty string", { domain });
|
|
1098
|
+
}
|
|
1099
|
+
const didDocument = options.fetchDidDocument ? await options.fetchDidDocument(domain) : await fetchDidDocument(domain);
|
|
1100
|
+
return verifyDidDocumentControllerDid(didDocument, expectedControllerDid);
|
|
1101
|
+
}
|
|
869
1102
|
function buildEip712Domain(name, version, chainId, verifyingContract) {
|
|
870
1103
|
return { name, version, chainId, verifyingContract };
|
|
871
1104
|
}
|
|
@@ -898,6 +1131,8 @@ function verifyEip712Signature(typedData, signature) {
|
|
|
898
1131
|
throw new OmaTrustError("INVALID_INPUT", "Failed to verify EIP-712 signature", { err });
|
|
899
1132
|
}
|
|
900
1133
|
}
|
|
1134
|
+
|
|
1135
|
+
// src/reputation/proof/dns-txt-record.ts
|
|
901
1136
|
function parseDnsTxtRecord(record) {
|
|
902
1137
|
if (!record || typeof record !== "string") {
|
|
903
1138
|
throw new OmaTrustError("INVALID_INPUT", "record must be a non-empty string", { record });
|
|
@@ -925,27 +1160,6 @@ function buildDnsTxtRecord(controllerDid) {
|
|
|
925
1160
|
const normalized = normalizeDid(controllerDid);
|
|
926
1161
|
return `v=1;controller=${normalized}`;
|
|
927
1162
|
}
|
|
928
|
-
async function verifyDnsTxtControllerDid(domain, expectedControllerDid) {
|
|
929
|
-
if (!domain || typeof domain !== "string") {
|
|
930
|
-
throw new OmaTrustError("INVALID_INPUT", "domain must be a non-empty string", { domain });
|
|
931
|
-
}
|
|
932
|
-
const expected = normalizeDid(expectedControllerDid);
|
|
933
|
-
const host = `_omatrust.${domain.toLowerCase().replace(/\.$/, "")}`;
|
|
934
|
-
let records;
|
|
935
|
-
try {
|
|
936
|
-
records = await resolveTxt(host);
|
|
937
|
-
} catch (err) {
|
|
938
|
-
throw new OmaTrustError("NETWORK_ERROR", "Failed to resolve DNS TXT records", { domain, err });
|
|
939
|
-
}
|
|
940
|
-
for (const recordParts of records) {
|
|
941
|
-
const record = recordParts.join("");
|
|
942
|
-
const parsed = parseDnsTxtRecord(record);
|
|
943
|
-
if (parsed.version === "1" && parsed.controller && normalizeDid(parsed.controller) === expected) {
|
|
944
|
-
return { valid: true, record };
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
return { valid: false, reason: "No TXT record matched expected controller DID" };
|
|
948
|
-
}
|
|
949
1163
|
|
|
950
1164
|
// src/reputation/verify.ts
|
|
951
1165
|
function parseChainId(input) {
|
|
@@ -1226,6 +1440,9 @@ async function getSchemaDetails(schemaRegistry, schemaUid) {
|
|
|
1226
1440
|
revocable: Boolean(details.revocable)
|
|
1227
1441
|
};
|
|
1228
1442
|
} catch (err) {
|
|
1443
|
+
if (isEasSchemaNotFoundError(err)) {
|
|
1444
|
+
throw new OmaTrustError("SCHEMA_NOT_FOUND", "Schema was not found", { schemaUid });
|
|
1445
|
+
}
|
|
1229
1446
|
if (err instanceof OmaTrustError) {
|
|
1230
1447
|
throw err;
|
|
1231
1448
|
}
|
|
@@ -1409,7 +1626,367 @@ function createEvidencePointerProof(url) {
|
|
|
1409
1626
|
issuedAt: Math.floor(Date.now() / 1e3)
|
|
1410
1627
|
};
|
|
1411
1628
|
}
|
|
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" };
|
|
1677
|
+
}
|
|
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
|
+
function assertConnectedWalletDid(input) {
|
|
1687
|
+
const normalized = normalizeDid(input);
|
|
1688
|
+
if (extractDidMethod(normalized) !== "pkh") {
|
|
1689
|
+
throw new OmaTrustError("INVALID_INPUT", "connectedWalletDid must be a did:pkh DID", {
|
|
1690
|
+
connectedWalletDid: input
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
return normalized;
|
|
1694
|
+
}
|
|
1695
|
+
function normalizeSubjectDid(input) {
|
|
1696
|
+
return normalizeDid(input);
|
|
1697
|
+
}
|
|
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
|
+
async function verifyDidWebOwnership(params) {
|
|
1736
|
+
const subjectDid = normalizeSubjectDid(params.subjectDid);
|
|
1737
|
+
const connectedWalletDid = assertConnectedWalletDid(params.connectedWalletDid);
|
|
1738
|
+
const domain = getDomainFromDidWeb(subjectDid);
|
|
1739
|
+
if (!domain) {
|
|
1740
|
+
throw new OmaTrustError("INVALID_INPUT", "subjectDid must be a did:web DID", {
|
|
1741
|
+
subjectDid: params.subjectDid
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
let dnsReason;
|
|
1745
|
+
try {
|
|
1746
|
+
const dnsResult = await verifyDnsTxtControllerDid2(domain, connectedWalletDid, {
|
|
1747
|
+
resolveTxt: params.resolveTxt,
|
|
1748
|
+
recordPrefix: params.recordPrefix
|
|
1749
|
+
});
|
|
1750
|
+
if (dnsResult.valid) {
|
|
1751
|
+
return {
|
|
1752
|
+
valid: true,
|
|
1753
|
+
method: "dns",
|
|
1754
|
+
details: `Verified via DNS TXT record at ${params.recordPrefix ?? "_controllers"}.${domain}`,
|
|
1755
|
+
subjectDid,
|
|
1756
|
+
connectedWalletDid
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
dnsReason = dnsResult.reason;
|
|
1760
|
+
} catch (error) {
|
|
1761
|
+
dnsReason = error instanceof Error ? error.message : "DNS TXT verification failed";
|
|
1762
|
+
}
|
|
1763
|
+
let didDocReason;
|
|
1764
|
+
try {
|
|
1765
|
+
const didDocumentResult = await verifyDidJsonControllerDid(domain, connectedWalletDid, {
|
|
1766
|
+
fetchDidDocument: params.fetchDidDocument
|
|
1767
|
+
});
|
|
1768
|
+
if (didDocumentResult.valid) {
|
|
1769
|
+
return {
|
|
1770
|
+
valid: true,
|
|
1771
|
+
method: "did-document",
|
|
1772
|
+
details: `Verified via DID document at https://${domain}/.well-known/did.json`,
|
|
1773
|
+
subjectDid,
|
|
1774
|
+
connectedWalletDid
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
didDocReason = didDocumentResult.reason;
|
|
1778
|
+
} catch (error) {
|
|
1779
|
+
didDocReason = error instanceof Error ? error.message : "DID document verification failed";
|
|
1780
|
+
}
|
|
1781
|
+
return {
|
|
1782
|
+
valid: false,
|
|
1783
|
+
reason: "DID ownership verification failed",
|
|
1784
|
+
details: `DNS check: ${dnsReason ?? "failed"}. DID document check: ${didDocReason ?? "failed"}.`,
|
|
1785
|
+
subjectDid,
|
|
1786
|
+
connectedWalletDid
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
async function verifyDidPkhOwnership(params) {
|
|
1790
|
+
const subjectDid = normalizeSubjectDid(params.subjectDid);
|
|
1791
|
+
const connectedWalletDid = assertConnectedWalletDid(params.connectedWalletDid);
|
|
1792
|
+
if (!isEvmDidPkh(subjectDid)) {
|
|
1793
|
+
throw new OmaTrustError("INVALID_INPUT", "subjectDid must be an EVM did:pkh DID", {
|
|
1794
|
+
subjectDid: params.subjectDid
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
const subjectAddress = getAddressFromDidPkh(subjectDid);
|
|
1798
|
+
const connectedWalletAddress = getAddressFromDidPkh(connectedWalletDid);
|
|
1799
|
+
const chainIdRaw = getChainIdFromDidPkh(subjectDid);
|
|
1800
|
+
if (!subjectAddress || !connectedWalletAddress || !chainIdRaw) {
|
|
1801
|
+
throw new OmaTrustError("INVALID_INPUT", "Could not parse did:pkh ownership inputs", {
|
|
1802
|
+
subjectDid: params.subjectDid,
|
|
1803
|
+
connectedWalletDid: params.connectedWalletDid
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
const chainId = Number(chainIdRaw);
|
|
1807
|
+
if (!Number.isFinite(chainId)) {
|
|
1808
|
+
throw new OmaTrustError("INVALID_INPUT", "Invalid chain id in subjectDid", {
|
|
1809
|
+
subjectDid: params.subjectDid
|
|
1810
|
+
});
|
|
1811
|
+
}
|
|
1812
|
+
const code = await params.provider.getCode(subjectAddress);
|
|
1813
|
+
const isContract = code !== "0x" && code !== "0x0";
|
|
1814
|
+
if (!isContract) {
|
|
1815
|
+
if (getAddress(subjectAddress) === getAddress(connectedWalletAddress)) {
|
|
1816
|
+
return {
|
|
1817
|
+
valid: true,
|
|
1818
|
+
method: "wallet",
|
|
1819
|
+
details: "Verified direct wallet ownership from matching did:pkh subject and connected wallet",
|
|
1820
|
+
subjectDid,
|
|
1821
|
+
connectedWalletDid
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
return {
|
|
1825
|
+
valid: false,
|
|
1826
|
+
reason: "EOA did:pkh subject does not match connected wallet",
|
|
1827
|
+
details: "For direct wallet did:pkh subjects, connectedWalletDid must match the subject DID.",
|
|
1828
|
+
subjectDid,
|
|
1829
|
+
connectedWalletDid
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1832
|
+
const controllingWalletDid = await discoverControllingWallet(params.provider, subjectAddress, chainId);
|
|
1833
|
+
if (params.txHash) {
|
|
1834
|
+
if (!controllingWalletDid) {
|
|
1835
|
+
return {
|
|
1836
|
+
valid: false,
|
|
1837
|
+
reason: "Could not discover controlling wallet",
|
|
1838
|
+
details: "Contract does not expose owner/admin/getOwner or a readable EIP-1967 admin slot for transfer verification.",
|
|
1839
|
+
subjectDid,
|
|
1840
|
+
connectedWalletDid
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
const tx = await params.provider.getTransaction(params.txHash);
|
|
1844
|
+
if (!tx) {
|
|
1845
|
+
return {
|
|
1846
|
+
valid: false,
|
|
1847
|
+
reason: "Transaction not found",
|
|
1848
|
+
details: `Transaction ${params.txHash} was not found on chain ${chainId}.`,
|
|
1849
|
+
subjectDid,
|
|
1850
|
+
connectedWalletDid,
|
|
1851
|
+
controllingWalletDid
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
const receipt = await params.provider.getTransactionReceipt(params.txHash);
|
|
1855
|
+
if (!receipt) {
|
|
1856
|
+
return {
|
|
1857
|
+
valid: false,
|
|
1858
|
+
reason: "Transaction not confirmed",
|
|
1859
|
+
details: "Transaction exists but is not yet confirmed.",
|
|
1860
|
+
subjectDid,
|
|
1861
|
+
connectedWalletDid,
|
|
1862
|
+
controllingWalletDid
|
|
1863
|
+
};
|
|
1864
|
+
}
|
|
1865
|
+
const controllingWalletAddress = getAddressFromDidPkh(controllingWalletDid);
|
|
1866
|
+
if (!tx.from || !controllingWalletAddress || getAddress(tx.from) !== getAddress(controllingWalletAddress)) {
|
|
1867
|
+
return {
|
|
1868
|
+
valid: false,
|
|
1869
|
+
reason: "Wrong sender",
|
|
1870
|
+
details: `Transfer must originate from controlling wallet ${controllingWalletDid}.`,
|
|
1871
|
+
subjectDid,
|
|
1872
|
+
connectedWalletDid,
|
|
1873
|
+
controllingWalletDid
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
if (!tx.to || getAddress(tx.to) !== getAddress(connectedWalletAddress)) {
|
|
1877
|
+
return {
|
|
1878
|
+
valid: false,
|
|
1879
|
+
reason: "Wrong recipient",
|
|
1880
|
+
details: `Transfer must be sent to connected wallet ${connectedWalletDid}.`,
|
|
1881
|
+
subjectDid,
|
|
1882
|
+
connectedWalletDid,
|
|
1883
|
+
controllingWalletDid
|
|
1884
|
+
};
|
|
1885
|
+
}
|
|
1886
|
+
const expectedAmount = calculateTransferAmount(
|
|
1887
|
+
subjectDid,
|
|
1888
|
+
connectedWalletDid,
|
|
1889
|
+
chainId,
|
|
1890
|
+
"shared-control"
|
|
1891
|
+
);
|
|
1892
|
+
const actualValue = BigInt(tx.value ?? 0n);
|
|
1893
|
+
if (actualValue !== expectedAmount) {
|
|
1894
|
+
return {
|
|
1895
|
+
valid: false,
|
|
1896
|
+
reason: "Wrong amount",
|
|
1897
|
+
details: `Transfer amount ${actualValue.toString()} does not match expected proof amount ${expectedAmount.toString()}.`,
|
|
1898
|
+
subjectDid,
|
|
1899
|
+
connectedWalletDid,
|
|
1900
|
+
controllingWalletDid
|
|
1901
|
+
};
|
|
1902
|
+
}
|
|
1903
|
+
await params.provider.getBlockNumber();
|
|
1904
|
+
await params.provider.getBlock(receipt.blockNumber);
|
|
1905
|
+
return {
|
|
1906
|
+
valid: true,
|
|
1907
|
+
method: "transfer",
|
|
1908
|
+
details: `Verified via transfer proof ${params.txHash}.`,
|
|
1909
|
+
subjectDid,
|
|
1910
|
+
connectedWalletDid,
|
|
1911
|
+
controllingWalletDid
|
|
1912
|
+
};
|
|
1913
|
+
}
|
|
1914
|
+
for (const pattern of OWNERSHIP_PATTERNS) {
|
|
1915
|
+
const ownerAddress = await readAddressFromContract(
|
|
1916
|
+
params.provider,
|
|
1917
|
+
subjectAddress,
|
|
1918
|
+
pattern.signature,
|
|
1919
|
+
pattern.method
|
|
1920
|
+
);
|
|
1921
|
+
if (ownerAddress && getAddress(ownerAddress) === getAddress(connectedWalletAddress)) {
|
|
1922
|
+
return {
|
|
1923
|
+
valid: true,
|
|
1924
|
+
method: "contract",
|
|
1925
|
+
details: `Verified via ${pattern.method}() ownership check.`,
|
|
1926
|
+
subjectDid,
|
|
1927
|
+
connectedWalletDid,
|
|
1928
|
+
controllingWalletDid: controllingWalletDid ?? void 0
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
try {
|
|
1933
|
+
const adminValue = await params.provider.getStorage(subjectAddress, EIP1967_ADMIN_SLOT);
|
|
1934
|
+
if (adminValue && adminValue !== "0x" && adminValue !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
|
|
1935
|
+
const adminAddress = getAddress(`0x${adminValue.slice(-40)}`);
|
|
1936
|
+
if (adminAddress === getAddress(connectedWalletAddress)) {
|
|
1937
|
+
return {
|
|
1938
|
+
valid: true,
|
|
1939
|
+
method: "contract",
|
|
1940
|
+
details: "Verified via EIP-1967 admin slot.",
|
|
1941
|
+
subjectDid,
|
|
1942
|
+
connectedWalletDid,
|
|
1943
|
+
controllingWalletDid: controllingWalletDid ?? buildEvmDidPkh(chainId, adminAddress)
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
} catch {
|
|
1948
|
+
}
|
|
1949
|
+
if (getAddress(subjectAddress) === getAddress(connectedWalletAddress) && controllingWalletDid) {
|
|
1950
|
+
return {
|
|
1951
|
+
valid: true,
|
|
1952
|
+
method: "minting-wallet",
|
|
1953
|
+
details: `Verified because connected wallet matches the contract DID address. Controlling wallet is ${controllingWalletDid}.`,
|
|
1954
|
+
subjectDid,
|
|
1955
|
+
connectedWalletDid,
|
|
1956
|
+
controllingWalletDid
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
return {
|
|
1960
|
+
valid: false,
|
|
1961
|
+
reason: "Contract ownership verification failed",
|
|
1962
|
+
details: controllingWalletDid ? `Connected wallet ${connectedWalletDid} does not match the controlling wallet ${controllingWalletDid} or the subject contract address ${subjectDid}.` : `Could not match connected wallet ${connectedWalletDid} to contract ownership for ${subjectDid}.`,
|
|
1963
|
+
subjectDid,
|
|
1964
|
+
connectedWalletDid,
|
|
1965
|
+
controllingWalletDid: controllingWalletDid ?? void 0
|
|
1966
|
+
};
|
|
1967
|
+
}
|
|
1968
|
+
async function verifySubjectOwnership(params) {
|
|
1969
|
+
const subjectDid = normalizeSubjectDid(params.subjectDid);
|
|
1970
|
+
const method = extractDidMethod(subjectDid);
|
|
1971
|
+
if (method === "web") {
|
|
1972
|
+
return verifyDidWebOwnership(params);
|
|
1973
|
+
}
|
|
1974
|
+
if (method === "pkh") {
|
|
1975
|
+
const didPkhParams = params;
|
|
1976
|
+
if (!didPkhParams.provider) {
|
|
1977
|
+
throw new OmaTrustError(
|
|
1978
|
+
"INVALID_INPUT",
|
|
1979
|
+
"provider is required for did:pkh ownership verification",
|
|
1980
|
+
{ subjectDid }
|
|
1981
|
+
);
|
|
1982
|
+
}
|
|
1983
|
+
return verifyDidPkhOwnership(didPkhParams);
|
|
1984
|
+
}
|
|
1985
|
+
throw new OmaTrustError("INVALID_INPUT", "Unsupported DID type for ownership verification", {
|
|
1986
|
+
subjectDid
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1412
1989
|
|
|
1413
|
-
export { buildDelegatedAttestationTypedData, buildDnsTxtRecord, buildEip712Domain, calculateAverageUserReviewRating, calculateTransferAmount, calculateTransferAmountFromAddresses, callControllerWitness, constructSeed, createEvidencePointerProof, createPopEip712Proof, createPopJwsProof, createTxEncodedValueProof, createTxInteractionProof, createX402OfferProof, createX402ReceiptProof, decodeAttestationData, deduplicateReviews, encodeAttestationData, extractAddressesFromDidDocument, extractExpirationTime, fetchDidDocument, formatSchemaUid, formatTransferAmount, getAttestation, getAttestationsForDid, getChainConstants, getExplorerAddressUrl, getExplorerTxUrl, getLatestAttestations, getMajorVersion, getOmaTrustProofEip712Types, getSchemaDetails, getSupportedChainIds, hashSeed, isChainSupported, listAttestations, normalizeSchema, parseDnsTxtRecord, prepareDelegatedAttestation, schemaToString, splitSignature, submitAttestation, submitDelegatedAttestation, verifyAttestation, verifyDidDocumentControllerDid, verifyDnsTxtControllerDid, verifyEip712Signature, verifyProof, verifySchemaExists };
|
|
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 };
|
|
1414
1991
|
//# sourceMappingURL=index.js.map
|
|
1415
1992
|
//# sourceMappingURL=index.js.map
|