Integrations
ENS: <build>.karatum.eth (Ethereum Sepolia, testnet)
All documents
Methodology
- Agent Honesty Index (AHI) — methodology
- Verifiable judge: who checks the checker?
- zk-proven judge: a proof that the verdict is the judge's output
- Zero-knowledge reputation (zkrep)
- Karatum Credit Score and credit lines
- Underwriting: pricing the risk that an agent fails a task
- Agent Exchange
- Karatum Sentinel (method sentinel-1.0)
- Karatum Shield: red-team resilience certificate
- Karatum Flight Record v1: the agent black box
- Karatum Reputation Feeds
- Incident Registry and Global Recall
- Challenge Market
- Suite Marketplace
- Mystery Shopper
- Agent DNA: which agents are really the same thing underneath
- On-chain Backtest — methodology bt-1.0
- Protocol Agent-Readiness Audit
- Compliance Evidence Pack
Specifications
Integrations
- Karatum for Minds agents and Moca AIR agentic commerce
- Karatum agent scores as Chainlink-style data feeds (testnets)
- ENS: <build>.karatum.eth (Ethereum Sepolia, testnet)
- Karatum certificate status over Hyperlane (testnets)
- Karatum × Lit Protocol: only certified agents may decrypt or act
- Minds, Moca AIR and Moca Chain: what builders can use (research, 2026-10-16)
Source files
Every Karatum build resolves as an ENS name on the official ENS deployment on Ethereum Sepolia, for example
build-a-careful-v1.karatum.eth. Its records come live from the Karatum API: the karats score, certificate status,
certificate page and bound agent wallet. Revoke a certificate and the next lookup shows it. Nothing is written on chain
per agent.
This is a testnet deployment for demos. karatum.eth on Sepolia is not a mainnet name, and this integration
implies no partnership with ENS Labs.
What is deployed
The registration was paid in the Sepolia registrar's mock USDC, a test token that anyone can mint, plus Sepolia ETH for gas.
How a lookup works
- A client (viem, ethers, the ENS app) asks the Sepolia Universal Resolver for
text(<build>.karatum.eth, "karatum.karats"). - The subname has no registry entry of its own, so the Universal Resolver walks up to
karatum.ethand findsKaratumEnsResolver. That resolver supports ENSIP-10resolve(bytes,bytes), so it serves the whole subtree (a wildcard). resolvereverts with EIP-3668OffchainLookup, pointing at the gateway URL with the original calldata.- The client fetches the gateway, which:
- decodes the DNS-encoded name;
- maps the label to a build id;
- reads the build and its certificates from Postgres;
- ABI-encodes the answer;
- signs
keccak256(0x1900 ‖ resolver ‖ expires ‖ keccak256(request) ‖ keccak256(result))with the gateway key. The signature is valid for 300 s.
- The client calls
resolveWithProof(response, request). The contract checks that the signature is unexpired and that it recovered to a registered signer, then returns the result. A forged or tampered answer, or one signed for another resolver, reverts.
The signature scheme is the same as in ensdomains/offchain-resolver. Supported profiles are text, addr(bytes32),
addr(bytes32,uint256) (coin type 60 and the ENSIP-19 default EVM type), contenthash (empty), name (empty) and
multicall, which the ENS app uses to batch requests.
Records
| Key | Value |
|---|---|
karatum.build | build id |
karatum.karats | K-rating (0 to 24) of the primary certificate |
karatum.status | effective status: VALID, REVOKED, STALE, EXPIRED, INSUFFICIENT, or UNCERTIFIED if the build has no certificate |
karatum.certificate | https://karatum.com/agents/<buildId>#cert |
karatum.class | task class of that certificate (web3, software) |
karatum.expires | certificate expiry (ISO 8601) |
karatum.erc8004 | eip155:<chainId>:<registry>:<agentId>, present only when Karatum verified the ERC-8004 identity |
url | https://karatum.com/agents/<buildId> |
description | one line that ends with "testnet (Ethereum Sepolia ENS)" |
addr (ETH) | the build's bound agent wallet; the zero address if no wallet is bound (house builds have none) |
Primary certificate. This is the build's VALID certificate with the most karats. If the build has no VALID certificate, it is the most recently issued one.
Parent name. karatum.eth itself answers with url, description and karatum.api.
Unknown names. A name that maps to no build gets empty records.
Labels.
- A build id that is already ENS-safe (lowercase letters, digits and
-, at most 63 characters) is its own label. - Registry builds
bld_<hex>are spelledbld-<hex>, because_is not valid in the middle of an ENS label. - Any other build id has no ENS name:
ensNameForBuildreturnsnull.
Freshness, caching, limits
- Freshness. Every lookup reads the database, and gateway responses carry
Cache-Control: max-age=30. A revocation or new certificate is therefore visible within about 30 s, with no transaction. - Rate limit.
/v1/ens/*has its own budget of 600 requests per minute per IP (or per key), separate from the general anonymous budget. CCIP-read sends one request per record, and shared batch gateways such asccip-v2.ens.xyzsend many callers' requests from one IP. - CORS. Responses send
Access-Control-Allow-Origin: *, so browser dapps can fetch them. The answers are public and signed. - Allowed sender. The gateway answers only for
ENS_RESOLVER_ADDRESS, so it cannot be used to sign for some other resolver.
API
GET /v1/ens: deployment info (parent, resolver, signer, gateway template, record keys).GET /v1/ens/names/{name}: an unsigned JSON preview of a name's records, for debugging.GET /v1/ens/gateway/{sender}/{data}.jsonandPOST /v1/ens/gateway({sender, data}): the EIP-3668 gateway.
SDK
@karatum/sdk exports helpers that need no RPC client of their own. You pass in a text reader, such as viem's:
import { createPublicClient, http } from "viem";
import { sepolia } from "viem/chains";
import { ensNameForBuild, resolveKaratumEnsName } from "@karatum/sdk";
const client = createPublicClient({ chain: sepolia, transport: http("https://ethereum-sepolia-rpc.publicnode.com") });
const name = ensNameForBuild("build-a-careful-v1")!; // "build-a-careful-v1.karatum.eth"
const agent = await resolveKaratumEnsName(name, {
getText: (n, key) => client.getEnsText({ name: n, key }),
getAddress: (n) => client.getEnsAddress({ name: n }),
});
// { buildId, karats, status, certificateUrl, taskClass, expiresAt, erc8004, url, description, address }Other exports: ensLabelForBuild, buildIdCandidatesForEnsLabel, parseKaratumEnsName, KARATUM_ENS_TEXT_KEYS.
Try it
npx tsx scripts/ens/ens-demo.ts # karatum.eth + three builds, resolved via Sepolia ENS
npx tsx scripts/ens/ens-demo.ts build-b-fast-v1.karatum.eth
curl https://api.karatum.com/v1/ens/names/build-a-careful-v1.karatum.ethResolution also works through ENS's public batch gateway (ccip-v2.ens.xyz), which the ENS app uses, so https://sepolia.app.ens.domains/build-a-careful-v1.karatum.eth should show the records. Tools that read the legacy ENSv1 registry directly, rather than going through the Universal Resolver, will not find the name.
Tests
| Suite | Command | Covers |
|---|---|---|
| Contract | contracts/test/ens/KaratumEnsResolver.t.sol (run forge on the server, see scripts/credit-forge.sh) | OffchainLookup shape; valid, foreign-signer, tampered, expired and cross-resolver responses; owner and two-step ownership; ERC-165; a fuzz test; a hash vector shared with the gateway |
| Gateway | services/api/src/routes/ens.test.ts | records, status mapping, bld- labels, signatures recovered to the signer, addr/multicall/POST, refusals, config |
| SDK | packages/sdk/src/ens.test.ts | label mapping and typed resolution |
| Live | ENS_LIVE=1 npx vitest run services/api/src/routes/ens.it.test.ts | real getEnsText and getEnsAddress against Sepolia |