Integrations
Karatum × Lit Protocol: only certified agents may decrypt or act
On this page
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
Testnet integration. Karatum reads come from the KaratumReputationFeed on Base, Ethereum, OP and Arbitrum Sepolia. There is no mainnet deployment and no partnership with Lit Protocol. This integration uses Lit's public developer API.
A secret is encrypted so that only an agent wallet certified on Karatum with karats ≥ N, a fresh standing and no active recall can decrypt it. The same gate can also co-sign a payload for a certified agent: the "act" half of the integration.
| Piece | Where |
|---|---|
| Lit Action (enforcement, runs on Lit) | packages/lit/src/karatum-gate.action.js |
TS API: encryptForCertifiedAgents, decryptAsAgent, attestAsAgent, verifyAttestation, gateSigner | packages/lit/src/gate.ts |
| Lit v3 REST client | packages/lit/src/chipotle.ts |
Local read-only twin of the rule (checkCertified) | packages/lit/src/check.ts |
| Lit EVM contract conditions for the same rule | packages/lit/src/conditions.ts |
| Demo | scripts/lit-demo.ts |
Which Lit network, and why not access-control conditions
The brief asked for Lit's free dev network (datil-dev / naga-dev) with EVM contract conditions. That path no longer exists.
- Naga (V1, including
naga-dev) was sunset on 2026-04-01 in the move to Lit v3. Datil stayed up only for migrations. Both ran on the Chronicle Yellowstone chain, whose RPC (yellowstone-rpc.litprotocol.com) no longer resolves.createLitClient({ network: nagaDev })from@lit-protocol/lit-client@8.3.1fails at connect, when it reads the staking contract. This was checked on 2026-10-27. - Lit v3 ("Chipotle") is the live network, at
https://api.chipotle.litprotocol.com/core/v1. Access-control conditions are gone: gating is plain JavaScript inside a Lit Action, and secrets are sealed withLit.Actions.Encrypt/Decryptunder a vault PKP. Chipotle is paid. Running an action costs $0.01 per second, with a $5 minimum top-up. It needs an account, and the docs list no free dev network. Read-only calls are free, including resolving an action's CID.
So the enforcement point is a Lit Action on Chipotle. buildEvmContractConditions() still emits the rule in the Lit SDK's evmContractConditions format, and that output validates against EvmContractConditionsSchema from @lit-protocol/access-control-conditions-schemas@8.0.2. It is the declarative form of the policy, but no live Lit network evaluates it today.
The rule
On the chain named in the policy, the gate calls getStandingWithStatus(agent, maxAge) on the feed at 0x3e98094028cF9879A82B66f62f16edCaEfE7f16b. It then applies this order:
recalled→ RECALLED (the feed ORs in the liveKaratumIncidentLogwhere one is wired)- never seen by the feed (
updatedAt == 0) → NOT_CERTIFIED stale(older thanmaxAge, where 0 means the feed heartbeat of 24 h; or the feed is paused) → STALE- no certified class (
classes == 0) → NOT_CERTIFIED karats < minKarats→ BELOW_MIN_KARATS- otherwise OK
evaluateStanding() in policy.ts is the same rule in TS. A unit test runs all 96 combinations through both copies and checks that they agree.
The EVM-conditions form has to differ. An ACC can't index into the feed's Standing tuple, so it reads isRecalled and isStale from the feed, plus status(agent, taskType) (s == VALID, karats >= N) from the Guard KaratumCertRegistry. That registry exists on Base Sepolia and Ethereum Sepolia only, and an agent passes only after its cert has been prove()d into the registry. The demo agent's registry status on Base Sepolia is NONE, even though its feed standing is 19K.
How the Lit Action is safe against its own callers
js_params are caller-controlled, so the action takes nothing security-relevant from them at decrypt time:
- The policy is sealed inside the ciphertext.
encryptseals{v, policy, data}.decryptuses the sealed policy, so a caller can't lowerminKarats. - The feed address and the RPC for each chain are constants of the action source. They are part of its CID, so a caller can't point the gate at a fake feed or a lying RPC. The RPCs are public endpoints; Alchemy is not used.
- The caller proves wallet ownership. The agent signs an EIP-191 request containing the version, op, agent,
keccak256(ciphertext)andissuedAt. The action rejects a different signer, a request for a different ciphertext, a request older than 300 s, and one more than 60 s in the future. - The action fails closed. An RPC error, an unknown op, a malformed envelope or a foreign vault all return
ok:falsewith no data. - Attestation.
attestsigns a statement (agent, chain, feed, karats, minKarats, payload hash, time) withgetLitActionPrivateKey(). That key is derived from the action CID. Verifiers pin the gate's signer address, fromgateSigner()or Lit'sgetLitActionWalletAddress(<CID>), and callverifyAttestation().
Residual risks:
- The plaintext goes back to whoever makes the API call that carries the agent's signature. That signature is bound to one ciphertext and lives 5 minutes.
- The vault PKP's group must permit only the gate CID. Any other action permitted on that PKP could decrypt the vault.
Current gate CID (computed by Lit for the committed source): QmZpczD4erLq7aVmuEzhtA6JXoTkciH1FvSz7RTPgASgF1. Any edit to the action file changes it.
Demo run (2026-10-27, server, Base Sepolia)
== 1. Lit network status
Datil / Naga (incl. naga-dev): yellowstone-rpc.litprotocol.com DOES NOT RESOLVE (ENOTFOUND)
Lit v3 (Chipotle) /version -> {"name":"lit-api-server","version":"0.1.0","commit_version":"v1.1.19"}
== 2. On-chain evidence
certified test agent 0x220A2FCa33365C39AB18fa293c70e1286dA79434 block 50956307 classes=1 karats=19 recalled=false stale=false -> OK
throwaway wallet 0x602A75d7850325A8fC0C036fb452b53865DC37DD block 50956309 classes=0 karats=0 recalled=false stale=true -> NOT_CERTIFIED
== 3. Lit Action CID (computed by Lit): QmZpczD4erLq7aVmuEzhtA6JXoTkciH1FvSz7RTPgASgF1
== 4. NOT RUN: LIT_API_KEY and LIT_VAULT_PKP_ID are not set (exit 2)Steps 1 to 3 are real. Step 4, the actual Lit encrypt, decrypt and attest calls, needs the owner setup below. The full flow is covered by unit tests that run the exact action bytes against a mocked Lit runtime: packages/lit/src/*.test.ts, 36 tests.
Owner setup
These steps need a person: creating the account and paying can't be automated here.
- Create a Chipotle account in the dashboard and add funds, minimum $5. A demo run uses about 5 action executions, each a few cents.
- Mint a vault PKP (dashboard or
POST /create_wallet) and note its id. - Create a group that contains the vault PKP and only the gate action CID above. Register the action from the source in
packages/lit/src/karatum-gate.action.js; the CID must match. - Create a usage API key that may run only that group.
- Run
doppler run -p _factory -c stg_karatum -- npx tsx scripts/lit-demo.ts --jsonand expect exit 0:- the certified agent decrypts;
- the throwaway wallet is refused with
NOT_CERTIFIED; - the attestation verifies.
Usage
import { ChipotleClient, encryptForCertifiedAgents, decryptAsAgent } from "@karatum/lit";
const ctx = { lit: new ChipotleClient({ apiKey: process.env.LIT_API_KEY! }), pkpId: process.env.LIT_VAULT_PKP_ID! };
const sealed = await encryptForCertifiedAgents("secret", { minKarats: 18, chain: "base-sepolia" }, ctx);
const { data, standing } = await decryptAsAgent(sealed, agentAccount /* viem LocalAccount */, ctx);
// throws LitGateError { code: "NOT_CERTIFIED" | "BELOW_MIN_KARATS" | "RECALLED" | "STALE" | ... }