Reputation SDK Reference
Canonical function reference for:
@oma3/omatrust/reputation
This is the implementation contract for reputation workflows, including attestation submission, querying, verification, proof functions, and the controller witness API client.
For end-to-end workflow guides covering proof lifecycles, see the Attestations Guide and the OMATrust Specification.
High-Level vs Advanced APIs
Most developers should start with the high-level functions:
submitAttestationprepareDelegatedAttestationsubmitDelegatedAttestationgetAttestationlistAttestationsverifyAttestationrequestControllerWitnessgetControllerAuthorizationverifySubjectOwnership
Advanced functions below are optional and intended for custom verifiers, specialized relays, and low-level integrations.
DID Canonicalization Note
For did:web identifiers, the SDK applies a canonical hostname normalization before building DIDs, hashing DIDs, deriving DID addresses, or verifying subject ownership.
Current did:web hostname normalization includes:
- lowercasing the host
- trimming surrounding whitespace
- removing a trailing
. - stripping a leading
www.
As a result, did:web:www.example.com and did:web:example.com normalize to the same canonical DID in the SDK. This behavior affects helpers built on DID normalization, including normalizeDidWeb, buildDidWeb, computeDidHash, didToAddress, and verifyDidWebOwnership.
Core Types
type Hex = `0x${string}`;
type Did = string;
// All proof types defined in the OMATrust Proof Specification (§5.3)
type ProofType =
| "pop-jws" // JWS signature proof (§5.3.2)
| "pop-eip712" // EIP-712 typed data signature proof (§5.3.3)
| "x402-receipt" // x402 service receipt proof (§5.3.4)
| "evidence-pointer" // URL-based evidence pointer (§5.3.5)
| "tx-encoded-value" // Deterministic transfer amount proof (§5.3.6)
| "tx-interaction" // On-chain contract interaction proof (§5.3.7)
| "x402-offer"; // x402 signed offer proof (§5.3.8)
type ProofPurpose = "shared-control" | "commercial-tx";
type SchemaField = { name: string; type: string; value?: unknown };
type AttestationQueryResult = {
uid: Hex;
schema: Hex;
attester: Hex;
recipient: Hex;
revocable: boolean;
revocationTime: bigint;
expirationTime: bigint;
time: bigint;
refUID: Hex;
data: Record<string, unknown>;
raw?: string;
};
// OMATrust Proof wrapper (§5.3.1). All proofs share this envelope.
type ProofWrapper = {
proofType: ProofType;
proofObject: unknown; // Native proof object, shape depends on proofType
proofPurpose?: ProofPurpose;
version?: number; // Default 1
issuedAt?: number; // Unix timestamp
expiresAt?: number; // Unix timestamp
};
// Proof wrapper with typed proofObject for tx-encoded-value (§5.3.6)
type TxEncodedValueProof = ProofWrapper & {
proofType: "tx-encoded-value";
proofPurpose: ProofPurpose;
proofObject: {
chainId: string;
txHash: string;
};
};
// Proof wrapper with typed proofObject for tx-interaction (§5.3.7)
type TxInteractionProof = ProofWrapper & {
proofType: "tx-interaction";
proofPurpose: "commercial-tx";
proofObject: {
chainId: string;
txHash: string;
};
};
// Proof wrapper with typed proofObject for pop-eip712 (§5.3.3)
type PopEip712Proof = ProofWrapper & {
proofType: "pop-eip712";
proofObject: {
domain: { name: string; version: string; chainId: number };
message: {
signer: string;
authorizedEntity: string;
signingPurpose: string;
creationTimestamp: number;
expirationTimestamp: number;
randomValue: Hex;
statement: string;
};
signature: Hex;
};
};
// Proof wrapper with typed proofObject for pop-jws (§5.3.2)
type PopJwsProof = ProofWrapper & {
proofType: "pop-jws";
proofObject: string; // Compact JWS string
};
// Proof wrapper with typed proofObject for x402-receipt (§5.3.4)
type X402ReceiptProof = ProofWrapper & {
proofType: "x402-receipt";
proofPurpose: "commercial-tx";
proofObject: Record<string, unknown>; // x402 receipt per x402 spec
};
// Proof wrapper with typed proofObject for x402-offer (§5.3.8)
type X402OfferProof = ProofWrapper & {
proofType: "x402-offer";
proofPurpose: "commercial-tx";
proofObject: Record<string, unknown>; // x402 signed offer per x402 spec
};
// Proof wrapper with typed proofObject for evidence-pointer (§5.3.5)
type EvidencePointerProof = ProofWrapper & {
proofType: "evidence-pointer";
proofPurpose: "shared-control";
proofObject: {
url: string;
};
};
type ChainConstants = {
base: bigint;
range: bigint;
decimals: number;
nativeSymbol: string;
};
Error Handling
All functions throw OmaTrustError (extends Error) with a stable code property. Consumers can catch and switch on error.code.
class OmaTrustError extends Error {
code: string;
details?: unknown;
}
| Code | Thrown by | Description |
|---|---|---|
INVALID_INPUT | All functions receiving malformed params | Missing required fields, wrong types, empty strings |
SCHEMA_NOT_FOUND | verifySchemaExists, getSchemaDetails | Schema UID does not exist on-chain |
ATTESTATION_NOT_FOUND | getAttestation | Attestation UID does not exist or has been revoked |
PROOF_VERIFICATION_FAILED | verifyAttestation, verifyProof | One or more proof checks failed |
NETWORK_ERROR | Any function making RPC or HTTP requests | Provider unreachable, timeout, HTTP error |
UNSUPPORTED_CHAIN | calculateTransferAmount, getChainConstants, hashSeed | Chain ID not in supported set |
import { submitAttestation } from "@oma3/omatrust/reputation";
try {
await submitAttestation(params);
} catch (err) {
if (err.code === "NETWORK_ERROR") {
// retry or switch RPC
}
}
Functions
submitAttestation(params)
type SubmitAttestationParams = {
signer: unknown; // ethers v6 Signer
chainId: number;
easContractAddress: Hex;
schemaUid: Hex;
schema: SchemaField[] | string;
data: Record<string, unknown>;
revocable?: boolean;
expirationTime?: bigint | number;
refUid?: Hex;
value?: bigint | number;
};
type SubmitAttestationResult = { uid: Hex; txHash: Hex; receipt?: unknown };
function submitAttestation(params: SubmitAttestationParams): Promise<SubmitAttestationResult>;
- Purpose: Submit a direct attestation on-chain.
- The
schemafield accepts either an array ofSchemaFieldobjects or an EAS schema string (e.g.,"string subject, uint8 rating, string comment"). - The
dataobject keys must match thenamefields in the schema. - If the schema includes a
subjectDidHashfield anddatacontains asubjectDID string, the hash is auto-computed. You do not need to hash it yourself. - Throws:
INVALID_INPUT,NETWORK_ERROR
prepareDelegatedAttestation(params)
type PrepareDelegatedAttestationParams = {
chainId: number;
easContractAddress: Hex;
schemaUid: Hex;
schema: SchemaField[] | string;
data: Record<string, unknown>;
attester: Hex;
nonce: bigint | number;
revocable?: boolean;
expirationTime?: bigint | number;
refUid?: Hex;
value?: bigint | number;
deadline?: bigint | number;
};
type PrepareDelegatedAttestationResult = {
delegatedRequest: Record<string, unknown>;
typedData: {
domain: Record<string, unknown>;
types: Record<string, unknown>;
message: Record<string, unknown>;
};
};
function prepareDelegatedAttestation(params: PrepareDelegatedAttestationParams): Promise<PrepareDelegatedAttestationResult>;
- Purpose: Build delegated attestation payload + EIP-712 typed data for signing.
- Same
schema/datasemantics assubmitAttestation(including autosubjectDidHash). - The returned
typedDatais passed directly tosigner.signTypedData(domain, types, message). - Throws:
INVALID_INPUT
submitDelegatedAttestation(params)
type SubmitDelegatedAttestationParams = {
relayUrl: string;
prepared: PrepareDelegatedAttestationResult;
signature: Hex | string;
attester?: Hex;
};
type SubmitDelegatedAttestationResult = { uid: Hex; txHash?: Hex; status: "submitted" | "confirmed" };
function submitDelegatedAttestation(params: SubmitDelegatedAttestationParams): Promise<SubmitDelegatedAttestationResult>;
- Purpose: Submit a signed delegated attestation via relay/gateway.
- The
relayUrlis the endpoint that accepts delegated attestation payloads (e.g., your API route or a shared gateway). See the Delegated Attestation API for the relay contract. - Throws:
INVALID_INPUT,NETWORK_ERROR
getAttestation(params)
type GetAttestationParams = {
uid: Hex;
provider: unknown; // ethers v6 Provider
easContractAddress: Hex;
schema?: SchemaField[] | string;
};
function getAttestation(params: GetAttestationParams): Promise<AttestationQueryResult>;
- Purpose: Read and decode one attestation by UID.
- If
schemais provided, the raw attestation data is decoded into thedatafield of the result. Otherwisedatawill be empty andrawwill contain the encoded bytes. - Throws:
ATTESTATION_NOT_FOUND,NETWORK_ERROR
listAttestations(params)
type ListAttestationsParams = {
subjectDid: Did;
provider: unknown; // ethers v6 Provider
easContractAddress: Hex;
schemas?: Hex[];
limit?: number;
fromBlock?: number;
toBlock?: number;
};
function listAttestations(params: ListAttestationsParams): Promise<AttestationQueryResult[]>;
- Purpose: Query attestations by subject DID and optional filters.
- Computes the DID hash internally to query on-chain.
- Throws:
INVALID_INPUT,NETWORK_ERROR
verifyAttestation(params)
type VerifyAttestationParams = {
attestation: AttestationQueryResult;
provider?: unknown; // ethers v6 Provider (required for on-chain checks)
checks?: ProofType[]; // Which proof types to verify; omit to verify all present
context?: Record<string, unknown>;
};
type VerifyAttestationResult = {
valid: boolean;
checks: Record<string, boolean>;
reasons: string[];
};
function verifyAttestation(params: VerifyAttestationParams): Promise<VerifyAttestationResult>;
- Purpose: Verify attestation validity plus proof checks.
- If
checksis omitted, runs all applicable checks based on the proof types present in the attestation'sproofsarray. contextis an optional bag of values passed to individual proof verifiers. Recognized keys:subjectDid(the subject DID) andcontrollerDid(the controller DID).reasonscontains human-readable explanations for any failed checks.- Throws:
PROOF_VERIFICATION_FAILED,NETWORK_ERROR
callControllerWitness(params)
type CallControllerWitnessParams = {
gatewayUrl: string;
attestationUid: Hex;
chainId: number;
easContract: Hex;
schemaUid: Hex;
subject: Did;
controller: Did;
timeoutMs?: number;
};
type CallControllerWitnessResult = {
ok: boolean;
method: "dns-txt" | "did-json";
details?: unknown;
};
function callControllerWitness(params: CallControllerWitnessParams): Promise<CallControllerWitnessResult>;
- Purpose: Call controller witness endpoint with automatic fallback (tries
dns-txtfirst, falls back todid-json). - The
gatewayUrlis passed in by the consumer — not hardcoded. You decide whether to call your own API route or a shared gateway. See the Controller Witness API for the raw endpoint contract. - Typically called after
submitAttestationorsubmitDelegatedAttestationcompletes. - Throws:
NETWORK_ERROR
requestControllerWitness(params)
type RequestControllerWitnessParams = {
subjectDid: Did;
controllerDid: Did;
gatewayUrl?: string; // Defaults to OMATrust production endpoint
chainId?: number; // Defaults to the API's active chain
timeoutMs?: number; // Default: 15000
};
type RequestControllerWitnessResult = {
success: boolean;
uid: string | null;
txHash: string;
blockNumber: number;
observedAt: number;
method: string;
};
function requestControllerWitness(params: RequestControllerWitnessParams): Promise<RequestControllerWitnessResult>;
- Purpose: Request a controller witness attestation from the OMATrust backend. This is the recommended replacement for
callControllerWitness. - Makes a single API call. The backend handles evidence discovery (DNS TXT, did.json), attestation submission, and write quota deduction.
- Requires an authenticated session (cookie-based for web clients).
- Throws:
NETWORK_ERROR,API_ERROR
getControllerAuthorization(params)
type W3CKeyPurpose =
| "authentication"
| "assertionMethod"
| "keyAgreement";
type GetControllerAuthorizationParams = {
controllerDid: string; // Full DID: did:pkh:eip155:*:0x... or did:jwk:<encoded>
subjectDid: Did;
provider: unknown; // ethers v6 Provider
chain?: string; // CAIP-2 identifier, defaults to "eip155:6623"
easContractAddress?: Hex; // If omitted, resolved from trust anchors
fromBlock?: number; // Defaults to 0 (full history)
resolveTxt?: (host: string) => Promise<string[][]>;
fetchDidDocument?: (domain: string) => Promise<Record<string, unknown>>;
purpose?: W3CKeyPurpose[]; // Defaults to ["authentication", "assertionMethod"]
};
type ControllerWitnessEvidence = {
uid: Hex;
issuedAt: bigint;
attester: string;
method?: "dns" | "did-document" | "manual" | "other";
};
type ControllerAuthorizationResult = {
authorized: boolean;
anchoredFrom: bigint | null;
until: bigint | null;
currentlyVerified: boolean;
liveMethod: "dns" | "did-document" | null;
controllerWitnesses: ControllerWitnessEvidence[];
keyBindingUid: Hex | null;
keyPurposeStatus: "matched" | "unknown" | "mismatch" | "not-required";
};
function getControllerAuthorization(params: GetControllerAuthorizationParams): Promise<ControllerAuthorizationResult>;
- Purpose: Determine the authorization window for a controller-subject pair. Returns the time range during which the controller was authorized to file subject-scoped attestations.
- Breaking change in 0.1.0-alpha.11: Renamed from
getAttesterAuthorization. Theattesterparameter (raw EVM address) is replaced bycontrollerDid(a full DID string). Now supportsdid:jwkcontrollers in addition to EVM addresses. - Controller witness matching uses
isSameControllerIdinternally — exact DID comparison + EVM address fallback (chain-agnostic) + JWK material match. - Key binding matching uses the
keyIdfield (DID) andpublicKeyJwkfield (fordid:jwk). - Checks on-chain controller-witness attestations, key-binding revocation and purpose status, and live DNS/did.json verification.
- The consumer calls this once per controller-subject pair, then filters their attestation list in memory using the returned window.
anchoredFromis the earliest timestamp of durable authorization evidence (first controller witness). Null when authorization is only currently verified by live DNS/did.json.untilis the end of the authorization window, set when a key binding revocation closes the window. Null if the window is still open.controllerWitnessesreturns structured evidence with metadata (UID, timestamp, attester, method) in oldest-first order.keyPurposeStatusindicates whether the key binding's purposes satisfy the requestedpurposefilter."mismatch"blocks authorization even if witnesses exist.- If
purposeis omitted, defaults to["authentication", "assertionMethod"]which covers the normal signing/control use case. - If
easContractAddressis omitted, the function fetches trust anchors and resolves the EAS address for the given chain. ThrowsUNSUPPORTED_CHAINif the chain is not in the trust anchors. - Throws:
UNSUPPORTED_CHAIN,INVALID_INPUT,NETWORK_ERROR
Migration from getAttesterAuthorization
// Before (0.1.0-alpha.10 and earlier):
import { getAttesterAuthorization } from "@oma3/omatrust/reputation";
const auth = await getAttesterAuthorization({
attester: "0x1234...abcd", // raw EVM address
subjectDid: "did:web:example.com",
provider,
});
// After (0.1.0-alpha.11):
import { getControllerAuthorization } from "@oma3/omatrust/reputation";
const auth = await getControllerAuthorization({
controllerDid: "did:pkh:eip155:1:0x1234...abcd", // full DID, not raw address
subjectDid: "did:web:example.com",
provider,
});
Key differences:
attester: Hex→controllerDid: string— accepts a full DID (did:pkh:eip155:*:0x...ordid:jwk:<encoded>)- Now supports
did:jwkcontrollers (not just EVM addresses) - Type renames:
GetAttesterAuthorizationParams→GetControllerAuthorizationParams,AttesterAuthorizationResult→ControllerAuthorizationResult - No deprecated aliases — old names are removed
Verifier usage pattern
import { getControllerAuthorization, listAttestations } from "@oma3/omatrust/reputation";
// 1. Get the authorization window (one call per controller-subject pair)
const auth = await getControllerAuthorization({
controllerDid: "did:pkh:eip155:1:0xABC...",
subjectDid: "did:web:example.com",
provider,
});
// 2. Filter attestations by the authorization window
const attestations = await listAttestations({ subjectDid: "did:web:example.com", provider, easContractAddress });
const authorized = attestations.filter(att => {
if (!auth.authorized) return false;
if (auth.until && att.time > auth.until) return false;
if (auth.anchoredFrom && att.time >= auth.anchoredFrom) return true;
// Fallback: trust current DNS/did.json for recent attestations (consumer policy)
if (auth.currentlyVerified) {
const sevenDaysAgo = BigInt(Math.floor(Date.now() / 1000) - 7 * 86400);
return att.time >= sevenDaysAgo;
}
return false;
});
Advanced Attestation Functions
encodeAttestationData(schema, data)
function encodeAttestationData(
schema: SchemaField[] | string,
data: Record<string, unknown>
): Hex;
- Purpose: ABI-encode attestation data using the EAS
SchemaEncoder. This is what gets stored on-chain as the attestation'sdatafield. - The
schemaparameter accepts either aSchemaField[]array or an EAS schema string (e.g.,"string subject, uint8 rating"). - The
dataobject keys must match the schema field names exactly. - Returns: ABI-encoded bytes as a hex string.
- Used internally by
submitAttestationandprepareDelegatedAttestation. Call this directly only if you're building custom submission logic. - Throws:
INVALID_INPUT
decodeAttestationData(schema, encodedData)
function decodeAttestationData(
schema: SchemaField[] | string,
encodedData: Hex
): Record<string, unknown>;
- Purpose: Decode ABI-encoded attestation bytes back into a typed object.
- Returns: Object keyed by schema field names with decoded values (e.g.,
{ subject: "did:web:example.com", rating: 5n }). - Used internally by
getAttestationwhenschemais provided. Call this directly if you have raw attestation bytes and need to decode them separately. - Throws:
INVALID_INPUT
extractExpirationTime(data)
function extractExpirationTime(
data: Record<string, unknown>
): bigint | number | undefined;
- Purpose: Extract the
expiresAttimestamp from decoded attestation data. - Returns: Timestamp as
bigintornumber, orundefinedifexpiresAtis not present or is null. - String values containing only digits are converted to
bigint.
validateAttestationData(schema, data)
type AttestationValidationError = {
schemaFieldName: string; // Name of the schema field that failed validation
expectedType: string; // ABI type declared in the schema (e.g., "uint256", "address")
providedType: string; // JS type of the value that was provided (e.g., "null", "string")
providedValue: unknown; // The actual value that was provided
};
function validateAttestationData(
schema: SchemaField[] | string,
data: Record<string, unknown>
): AttestationValidationError[];
- Purpose: Validate attestation data against a schema before submitting on-chain. Returns an array of field-level errors for any values that don't match their declared ABI types.
- Returns an empty array if all fields are valid.
- Validates:
uint*/int*(numeric values),string,string[],bool,address(via ethersisAddress),bytes, and fixed-sizebytes1–bytes32. - Used internally by
encodeAttestationData. Call this directly if you want to surface validation errors to users before attempting a transaction. - This is a client-side check to prevent on-chain reverts from malformed data.
buildDelegatedAttestationTypedData(params)
function buildDelegatedAttestationTypedData(
params: PrepareDelegatedAttestationParams
): { domain: Record<string, unknown>; types: Record<string, unknown>; message: Record<string, unknown> };
- Purpose: Build EIP-712 typed data for delegated attestation signing. This is the lower-level building block used by
prepareDelegatedAttestation. - Call this directly only if you need the typed data without the full
delegatedRequestwrapper. - Throws:
INVALID_INPUT
buildDelegatedTypedDataFromEncoded(params)
type BuildDelegatedTypedDataFromEncodedParams = {
chainId: number;
easContractAddress: Hex;
schemaUid: Hex;
encodedData: Hex;
recipient: Hex;
attester: Hex;
nonce: bigint | number;
revocable?: boolean;
expirationTime?: bigint | number;
refUid?: Hex;
value?: bigint | number;
deadline?: bigint | number;
};
function buildDelegatedTypedDataFromEncoded(
params: BuildDelegatedTypedDataFromEncodedParams
): { domain: Record<string, unknown>; types: Record<string, unknown>; message: Record<string, unknown> };
- Purpose: Build delegated attestation EIP-712 typed data from pre-encoded bytes.
- Use this when your relay/server receives already-encoded attestation bytes and must independently rebuild typed data for verification or signing checks.
- Unlike
buildDelegatedAttestationTypedData, this function does not encode schema/data and does not resolve recipient from DID input. It usesencodedDataandrecipientexactly as provided.
splitSignature(signature)
function splitSignature(
signature: Hex | string
): { v: number; r: Hex; s: Hex };
- Purpose: Split a 65-byte signature into
{v, r, s}components for EAS contract calls. - Throws:
INVALID_INPUT
getAttestationsForDid(params)
function getAttestationsForDid(
params: ListAttestationsParams
): Promise<AttestationQueryResult[]>;
- Purpose: Low-level DID subject query helper. Same as
listAttestationsbut without deduplication or sorting. UselistAttestationsunless you need raw results. - Throws:
NETWORK_ERROR
getLatestAttestations(params)
type GetLatestAttestationsParams = {
provider: unknown;
easContractAddress: Hex;
schemas?: Hex[];
limit?: number;
fromBlock?: number;
};
function getLatestAttestations(
params: GetLatestAttestationsParams
): Promise<AttestationQueryResult[]>;
- Purpose: Fetch the most recent attestations across schemas, not filtered by subject. Useful for dashboards and monitoring.
- Throws:
NETWORK_ERROR
deduplicateReviews(attestations)
function deduplicateReviews(
attestations: AttestationQueryResult[]
): AttestationQueryResult[];
- Purpose: Deduplicate User Review attestations by attester + subject + major version. When the same attester reviews the same subject multiple times, only the latest attestation (by timestamp) is kept. This implements the OMATrust supersession logic defined in the Reputation Specification §7.1.4.
calculateAverageUserReviewRating(attestations)
function calculateAverageUserReviewRating(
attestations: AttestationQueryResult[]
): number;
- Purpose: Calculate the average
ratingValuefield across an array of User Review attestations. This function is specific to the User Review schema (Reputation Specification §7.1) and expects each attestation'sdatato contain a numericratingValuefield (1–5). - Returns: Average as a floating-point number.
getMajorVersion(version)
function getMajorVersion(version: string): number;
- Purpose: Extract the major version number from a semver string (e.g.,
"2.1.0"→2).
verifySchemaExists(schemaRegistry, schemaUid)
function verifySchemaExists(
schemaRegistry: unknown,
schemaUid: Hex
): Promise<boolean>;
- Purpose: Check if a schema UID exists in the EAS SchemaRegistry contract.
- The
schemaRegistryparameter is an EAS SDKSchemaRegistryinstance, created vianew SchemaRegistry(address)from@ethereum-attestation-service/eas-sdk. The SchemaRegistry is the on-chain contract that stores all registered attestation schemas — each schema gets a unique UID when registered, and this function checks whether a given UID exists. - Throws:
NETWORK_ERROR
getSchemaDetails(schemaRegistry, schemaUid)
function getSchemaDetails(
schemaRegistry: unknown,
schemaUid: Hex
): Promise<{ uid: Hex; schema: string; resolver: Hex; revocable: boolean }>;
- Purpose: Fetch the full schema record from the EAS SchemaRegistry contract.
- Returns: Schema record with the schema string (e.g.,
"string subject, uint8 rating"), resolver address, and revocability flag. - Throws:
SCHEMA_NOT_FOUND,NETWORK_ERROR
formatSchemaUid(schemaUid)
function formatSchemaUid(schemaUid: string): Hex;
- Purpose: Ensure a schema UID has the
0xprefix and is lowercase. Normalizes inconsistent formatting.
Advanced Proof Functions
The OMATrust Proof Specification defines seven proof types. This section provides SDK functions for creating and verifying each type. For the full proof specification, see the OMATrust Proof Specification.
Proof Creation
createTxEncodedValueProof(chainId, txHash, purpose)
function createTxEncodedValueProof(
chainId: number,
txHash: Hex,
purpose: ProofPurpose
): TxEncodedValueProof;
- Purpose: Build a
tx-encoded-valueproof wrapper from a completed native-value transaction (§5.3.6).
createTxInteractionProof(chainId, txHash)
function createTxInteractionProof(
chainId: number,
txHash: Hex
): TxInteractionProof;
- Purpose: Build a
tx-interactionproof wrapper from a completed smart contract transaction (§5.3.7). Used when a reviewer interacted with a contract-based service.
createPopEip712Proof(params)
type CreatePopEip712ProofParams = {
signer: string; // Subject address (the signer)
authorizedEntity: string; // Controller DID
signingPurpose: ProofPurpose;
chainId: number;
creationTimestamp?: number;
expirationTimestamp?: number;
randomValue?: Hex;
statement?: string; // Defaults to "This is not a transaction or asset approval."
};
function createPopEip712Proof(
params: CreatePopEip712ProofParams,
signFn: (typedData: Record<string, unknown>) => Promise<Hex>
): Promise<PopEip712Proof>;
- Purpose: Build a
pop-eip712proof by constructing the canonical OMATrust EIP-712 typed data (§5.3.3) and signing it with the provided signing function. - The
signFncallback receives the full EIP-712 typed data and should return the signature. This keeps the SDK signer-agnostic — you can use ethers, viem, or any wallet. - Throws:
INVALID_INPUT
createPopJwsProof(params)
type CreatePopJwsProofParams = {
issuer: Did; // Subject DID
audience: Did; // Controller DID
purpose: ProofPurpose;
issuedAt?: number;
expiresAt?: number;
nonce?: string;
};
function createPopJwsProof(
params: CreatePopJwsProofParams,
signFn: (payload: Record<string, unknown>, header: Record<string, unknown>) => Promise<string>
): Promise<PopJwsProof>;
- Purpose: Build a
pop-jwsproof by constructing the JWS payload and header per §5.3.2 and signing with the provided callback. - The
signFnreceives the JWS payload and header objects and should return the compact JWS string. - Throws:
INVALID_INPUT
createEvidencePointerProof(url)
function createEvidencePointerProof(
url: string
): EvidencePointerProof;
- Purpose: Build an
evidence-pointerproof wrapper pointing to a publicly accessible URL containing evidence (§5.3.5). The URL should resolve to either an embedded cryptographic proof or a handle-link statement inv=1;controller=<DID>format.
createX402ReceiptProof(receipt)
function createX402ReceiptProof(
receipt: Record<string, unknown>
): X402ReceiptProof;
- Purpose: Build an
x402-receiptproof wrapper from an x402 service receipt object (§5.3.4). The receipt is the object fromextensions["offer-receipt"].info.receiptin an x402 Settlement Response.
createX402OfferProof(offer)
function createX402OfferProof(
offer: Record<string, unknown>
): X402OfferProof;
- Purpose: Build an
x402-offerproof wrapper from an x402 signed offer object (§5.3.8). The offer is fromextensions["offer-receipt"].info.offers[*]in an x402 Payment Requirements response.
Proof Verification
verifyProof(proof, context)
type VerifyProofParams = {
proof: ProofWrapper;
provider?: unknown; // ethers v6 Provider (required for on-chain proofs)
expectedSubjectDid?: Did;
expectedControllerDid?: Did;
};
type VerifyProofResult = {
valid: boolean;
proofType: ProofType;
reason?: string;
};
function verifyProof(
params: VerifyProofParams
): Promise<VerifyProofResult>;
- Purpose: Verify a single proof wrapper of any type. Routes to the appropriate type-specific verification logic based on
proof.proofType. - For
tx-encoded-value: fetches the on-chain transaction and checks the transfer amount matches the deterministic value. - For
tx-interaction: fetches the transaction and confirms sender/recipient match the expected attester/subject. - For
pop-eip712: recovers the signer from the EIP-712 signature and validates against the canonical OMATrust schema. - For
pop-jws: validates the JWS signature against the embedded JWK and checks claims. - For
x402-receiptwithformat: "jws": performs cryptographic JWS verification, returnsdid:jwkas the durable controller DID. - For
x402-receiptwithformat: "eip712": performs cryptographic EIP-712 verification, recovers the signer address. - For
x402-offerwithformat: "jws": performs cryptographic JWS verification. - For
x402-offerwithformat: "eip712": performs cryptographic EIP-712 verification. - For
x402-receipt/x402-offerwith other formats: backward-compatible shape-only validation. - For
evidence-pointer: fetches the URL and validates the evidence artifact (embedded crypto proof or handle-link statement). - Throws:
PROOF_VERIFICATION_FAILED,NETWORK_ERROR
x402 JWS Verification
These functions verify x402 signed offers and receipts that use JWS Compact Serialization. They support two key resolution paths: embedded jwk (self-contained, offline-verifiable) and kid resolution (resolves a DID URL to find the public key).
All JWS verification functions return a did:jwk as the durable controller DID. This is the identity you pass to getControllerAuthorization — not the kid DID URL, which is a mutable reference.
For the full verification → authorization flow, see Client Verification.
verifyX402JwsArtifact(artifact, options?)
type X402JwsArtifact = {
format: "jws";
signature: string; // JWS Compact Serialization
};
type JwsVerificationResult = {
valid: true;
header: Record<string, unknown>;
payload: Record<string, unknown>;
kid: string;
publicKeyJwk: Record<string, unknown>;
publicKeySource: "embedded-jwk" | "kid-resolution";
publicKeyDid: string; // did:jwk — durable controller DID
};
type JwsVerificationFailure = {
valid: false;
error: { code: string; message: string };
};
type JwsVerifyOptions = {
fetchDidDocument?: (domain: string) => Promise<Record<string, unknown>>;
};
function verifyX402JwsArtifact(
artifact: X402JwsArtifact,
options?: JwsVerifyOptions
): Promise<JwsVerificationResult | JwsVerificationFailure>;
- Purpose: Core JWS verification for any x402 artifact. Parses the compact JWS, obtains the public key (from embedded
jwkor by resolvingkid), verifies the signature, and derives thedid:jwk. - Does not validate payload shape — use
verifyX402JwsOfferorverifyX402JwsReceiptfor payload validation. - When both
kidandjwkare present, usesjwkfor verification and rejects ifkidresolves to a conflicting key. - Throws:
PROOF_VERIFICATION_FAILED
verifyX402JwsOffer(artifact, options?)
function verifyX402JwsOffer(
artifact: X402JwsArtifact,
options?: JwsVerifyOptions
): Promise<JwsVerificationResult | JwsVerificationFailure>;
- Purpose: Verify a JWS-signed x402 offer. Performs signature verification and validates the offer payload contains required fields:
version,resourceUrl,scheme,network,asset,payTo,amount. - Throws:
PROOF_VERIFICATION_FAILED
verifyX402JwsReceipt(artifact, options?)
function verifyX402JwsReceipt(
artifact: X402JwsArtifact,
options?: JwsVerifyOptions
): Promise<JwsVerificationResult | JwsVerificationFailure>;
- Purpose: Verify a JWS-signed x402 receipt. Performs signature verification and validates the receipt payload contains required fields:
version,network,resourceUrl,payer,issuedAt. - Throws:
PROOF_VERIFICATION_FAILED
x402 EIP-712 Verification
These functions verify x402 signed offers and receipts that use EIP-712 typed-data signatures. The signer address is recovered directly from the signature — no DID resolution needed.
All EIP-712 artifacts use a fixed domain (name: "x402 offer"/"x402 receipt", version: "1", chainId: 1). The chainId: 1 is intentional — EIP-712 is used as an off-chain signing format; the actual payment network is in the payload.
verifyX402Eip712Artifact(artifact, artifactType)
type X402Eip712Artifact = {
format: "eip712";
payload: Record<string, unknown>;
signature: string; // hex-encoded, 0x-prefixed, 65 bytes
};
type Eip712VerificationResult = {
valid: true;
payload: Record<string, unknown>;
signer: string; // recovered EVM address (checksummed)
artifactType: "offer" | "receipt";
};
type Eip712VerificationFailure = {
valid: false;
error: { code: string; message: string };
payload?: Record<string, unknown>;
signer?: string;
};
function verifyX402Eip712Artifact(
artifact: X402Eip712Artifact,
artifactType: "offer" | "receipt"
): Eip712VerificationResult | Eip712VerificationFailure;
- Purpose: Core EIP-712 verification for any x402 artifact. Constructs the canonical EIP-712 typed data, recovers the signer address, and validates the payload shape.
- Throws:
PROOF_VERIFICATION_FAILED
verifyX402Eip712Offer(artifact)
function verifyX402Eip712Offer(
artifact: X402Eip712Artifact
): Eip712VerificationResult | Eip712VerificationFailure;
- Purpose: Verify an EIP-712-signed x402 offer. Recovers the signer and validates offer payload fields.
verifyX402Eip712Receipt(artifact)
function verifyX402Eip712Receipt(
artifact: X402Eip712Artifact
): Eip712VerificationResult | Eip712VerificationFailure;
- Purpose: Verify an EIP-712-signed x402 receipt. Recovers the signer and validates receipt payload fields.
tx-encoded-value Helpers
calculateTransferAmount(subject, counterparty, chainId, purpose)
function calculateTransferAmount(
subject: Did,
counterparty: Did,
chainId: number,
purpose: ProofPurpose
): bigint;
- Purpose: Compute the deterministic transfer amount for a tx-encoded-value proof (§5.3.6).
- The amount is derived from the DID hashes of both parties, the chain ID, and the proof purpose. It is deterministic — the same inputs always produce the same amount.
- Returns: Amount in the chain's smallest unit (e.g., wei for EVM chains).
- Throws:
INVALID_INPUT,UNSUPPORTED_CHAIN
calculateTransferAmountFromAddresses(subjectAddress, counterpartyAddress, chainId, purpose)
function calculateTransferAmountFromAddresses(
subjectAddress: string,
counterpartyAddress: string,
chainId: number,
purpose: ProofPurpose
): bigint;
- Purpose: Convenience wrapper that accepts raw addresses instead of DIDs. Internally builds
did:pkhDIDs from the addresses and delegates tocalculateTransferAmount. - Throws:
INVALID_INPUT,UNSUPPORTED_CHAIN
constructSeed(subjectDidHash, counterpartyDidHash, purpose)
function constructSeed(
subjectDidHash: Hex,
counterpartyDidHash: Hex,
purpose: ProofPurpose
): Uint8Array;
- Purpose: Build the canonical JCS (RFC 8785) seed object per §5.3.6.3, canonicalize it, and return the UTF-8 bytes. This seed is the input to
hashSeed.
hashSeed(seedBytes, chainId)
function hashSeed(
seedBytes: Uint8Array,
chainId: number
): Hex;
- Purpose: Hash the seed bytes using the chain-appropriate algorithm (keccak256 for EVM chains, SHA-256 for others).
- Throws:
UNSUPPORTED_CHAIN
getChainConstants(chainId, purpose)
function getChainConstants(
chainId: number,
purpose: ProofPurpose
): ChainConstants;
- Purpose: Return the BASE and RANGE constants for a given chain and proof purpose. These are spec-defined values (Appendix A) used in the transfer amount calculation.
- Returns:
ChainConstantswithbase(minimum amount),range(amount range),decimals(native token decimals), andnativeSymbol(e.g.,"ETH","MATIC"). - Throws:
UNSUPPORTED_CHAIN
formatTransferAmount(amount, chainId)
function formatTransferAmount(
amount: bigint | number,
chainId: number
): string;
- Purpose: Format a transfer amount for human-readable display (e.g.,
"0.000000000000001234 ETH"). - Throws:
UNSUPPORTED_CHAIN
getSupportedChainIds()
function getSupportedChainIds(): number[];
- Purpose: List all chain IDs that support tx-encoded-value proofs.
isChainSupported(chainId)
function isChainSupported(chainId: number): boolean;
- Purpose: Check if a specific chain ID supports tx-encoded-value proofs.
evidence-pointer Helpers
verifyDnsTxtControllerDid(domain, expectedControllerDid)
function verifyDnsTxtControllerDid(
domain: string,
expectedControllerDid: Did,
options?: {
resolveTxt?: (host: string) => Promise<string[][]>;
recordPrefix?: string;
}
): Promise<{ valid: boolean; record?: string; reason?: string }>;
- Purpose: Verify that the
_controllers.<domain>DNS TXT record contains the expected controller DID. - Uses
isSameControllerIdinternally for matching — handlesdid:jwkand chain-agnostic EVM address comparison. recordPrefixdefaults to_controllers.- In Node.js/server runtimes, the default export resolves DNS TXT directly.
- In browser bundles, DNS TXT verification requires an injected
resolveTxtfunction. Without one, the browser export throwsNETWORK_ERROR. - Throws:
NETWORK_ERROR
parseDnsTxtRecord(record)
function parseDnsTxtRecord(
record: string
): { version?: string; controllers: Did[]; controller?: Did };
- Purpose: Parse a DNS TXT record or evidence string in
v=1;controller=did:pkh:...format. A single record may contain multiplecontroller=entries (e.g.,v=1;controller=did:pkh:eip155:66238:0x...;controller=did:pkh:eip155:1:0x...). - Returns
controllers— an array of all controller DIDs found in the record. Use this field to iterate over all declared controllers. - Throws:
INVALID_INPUT
buildDnsTxtRecord(controllerDid)
function buildDnsTxtRecord(controllerDid: Did): string;
- Purpose: Build the expected
v=1;controller=<DID>evidence string for a given controller DID.
fetchDidDocument(domain)
function fetchDidDocument(
domain: string
): Promise<Record<string, unknown>>;
- Purpose: Fetch
https://<domain>/.well-known/did.jsonand return the parsed DID document. - Throws:
NETWORK_ERROR
verifyDidJsonControllerDid(domain, expectedControllerDid, options?)
function verifyDidJsonControllerDid(
domain: string,
expectedControllerDid: Did,
options?: {
fetchDidDocument?: (domain: string) => Promise<Record<string, unknown>>;
}
): Promise<{ valid: boolean; reason?: string }>;
- Purpose: Verify that
https://<domain>/.well-known/did.jsoncontains the expected controller DID. - This is the
.well-knowncounterpart toverifyDnsTxtControllerDid. - Internally, it fetches the DID document and then applies the same controller-address matching logic as
verifyDidDocumentControllerDid. - Throws:
INVALID_INPUT,NETWORK_ERROR
verifyDidDocumentControllerDid(didDocument, expectedControllerDid)
function verifyDidDocumentControllerDid(
didDocument: Record<string, unknown>,
expectedControllerDid: Did
): { valid: boolean; reason?: string };
- Purpose: Verify that a DID document's controller or verificationMethod addresses match the expected controller DID.
- For
did:jwkcontrollers, compares againstpublicKeyJwkin verification methods. - For
did:pkh, compares EVM addresses (chain-agnostic).
extractEvmAddressesFromDidDocument(didDocument)
function extractEvmAddressesFromDidDocument(
didDocument: Record<string, unknown>
): string[];
- Purpose: Extract all checksummed EVM addresses from a DID document's
verificationMethodarray (fromblockchainAccountIdandpublicKeyHexfields). - Renamed in 0.1.0-alpha.11 from
extractAddressesFromDidDocumentto clarify it is EVM-specific.
extractJwksFromDidDocument(didDocument)
function extractJwksFromDidDocument(
didDocument: Record<string, unknown>
): Array<Record<string, unknown>>;
- Purpose: Extract
publicKeyJwkobjects from verification methods in a DID document. - Returns an array of JWK objects found in the document's verification methods.
Subject Ownership Helpers
These functions are the SDK-level verification primitives for subject ownership. They are the closest reusable equivalent to the verification portion of app-registry-frontend's verify-and-attest flow, but they do not write attestations or perform app-specific orchestration.
verifyDidWebOwnership(params)
type VerifyDidWebOwnershipParams = {
subjectDid: Did;
connectedWalletDid: Did; // must be did:pkh
resolveTxt?: (host: string) => Promise<string[][]>;
recordPrefix?: string; // defaults to "_controllers"
fetchDidDocument?: (domain: string) => Promise<Record<string, unknown>>;
};
type SubjectOwnershipVerificationResult = {
valid: boolean;
method?: "dns" | "did-document" | "wallet" | "contract" | "minting-wallet" | "transfer";
reason?: string;
details?: string;
subjectDid: Did;
connectedWalletDid: Did;
controllingWalletDid?: Did;
};
function verifyDidWebOwnership(
params: VerifyDidWebOwnershipParams
): Promise<SubjectOwnershipVerificationResult>;
- Purpose: Verify ownership of a
did:websubject against a connected wallet DID. - The
subjectDidis canonicalized before verification. Fordid:web, that includes lowercasing the host, removing a trailing., and stripping a leadingwww.. - Verification order:
- DNS TXT check at
_controllers.<domain> - DID document check at
https://<domain>/.well-known/did.json
- DNS TXT check at
- Returns
method: "dns"ormethod: "did-document"on success. - Best used in backend/server runtimes. In browser runtimes, provide
resolveTxtif you want DNS verification there. - Throws:
INVALID_INPUT,NETWORK_ERROR
verifyDidPkhOwnership(params)
type EvmOwnershipProvider = {
call(transaction: { to: string; data: string }): Promise<string>;
getCode(address: string): Promise<string>;
getStorage(address: string, slot: string): Promise<string>;
getTransaction(hash: string): Promise<{
from?: string | null;
to?: string | null;
value?: bigint | string | number | null;
blockNumber?: number | null;
} | null>;
getTransactionReceipt(hash: string): Promise<{ blockNumber: number } | null>;
getBlockNumber(): Promise<number>;
getBlock(blockNumber: number): Promise<{ timestamp: number } | null>;
};
type VerifyDidPkhOwnershipParams = {
subjectDid: Did; // must be an EVM did:pkh
connectedWalletDid: Did; // must be did:pkh
provider: EvmOwnershipProvider;
txHash?: Hex | string;
};
function verifyDidPkhOwnership(
params: VerifyDidPkhOwnershipParams
): Promise<SubjectOwnershipVerificationResult>;
- Purpose: Verify ownership of an EVM
did:pkhsubject. - Supported cases:
- direct wallet DID match
- contract ownership via
owner() - contract ownership via
admin() - contract ownership via
getOwner() - EIP-1967 admin slot lookup
- transfer-proof verification when
txHashis provided
- Returns one of:
method: "wallet"method: "contract"method: "minting-wallet"method: "transfer"
- Throws:
INVALID_INPUT,NETWORK_ERROR
verifySubjectOwnership(params)
type VerifySubjectOwnershipParams =
| VerifyDidWebOwnershipParams
| VerifyDidPkhOwnershipParams;
function verifySubjectOwnership(
params: VerifySubjectOwnershipParams
): Promise<SubjectOwnershipVerificationResult>;
- Purpose: Dispatch subject ownership verification based on the DID method.
did:websubjects route toverifyDidWebOwnership.did:pkhsubjects route toverifyDidPkhOwnership.- Throws
INVALID_INPUTfor unsupported DID methods or missing required inputs such as the EVM provider fordid:pkh.
EIP-712 Helpers
verifyEip712Signature(typedData, signature)
function verifyEip712Signature(
typedData: { domain: Record<string, unknown>; types: Record<string, unknown>; message: Record<string, unknown> },
signature: Hex | string
): { valid: boolean; signer?: string };
- Purpose: Recover the signer address from an EIP-712 typed data signature and verify it.
- Throws:
INVALID_INPUT
buildEip712Domain(name, version, chainId, verifyingContract)
function buildEip712Domain(
name: string,
version: string,
chainId: number,
verifyingContract: Hex
): { name: string; version: string; chainId: number; verifyingContract: Hex };
- Purpose: Build a standard EIP-712 domain separator object.
getOmaTrustProofEip712Types()
function getOmaTrustProofEip712Types(): {
primaryType: string;
types: Record<string, Array<{ name: string; type: string }>>;
};
- Purpose: Return the canonical OMATrust EIP-712 types and primaryType for
pop-eip712proofs as defined in the Proof Specification §5.3.3. Useful for building signing requests or verifying proofs without hardcoding the schema.
Explorer Helpers
getExplorerTxUrl(chainId, txHash)
function getExplorerTxUrl(chainId: number, txHash: Hex): string;
- Purpose: Build a block explorer URL for a transaction (e.g., Etherscan, Basescan).
- Throws:
UNSUPPORTED_CHAIN
getExplorerAddressUrl(chainId, address)
function getExplorerAddressUrl(chainId: number, address: string): string;
- Purpose: Build a block explorer URL for an address.
- Throws:
UNSUPPORTED_CHAIN