Karatum Guard · testnets

A certificate the wallet enforces

Karatum certifies, per agent build and task class, that an agent's verified outcomes are good enough (VALID, STALE or EXPIRED). Karatum Guard moves that verdict into the wallet: a Safe or an ERC-4337 smart account operated by an AI agent executes a transaction only while the agent's certificate for that kind of task is VALID on-chain, the target is allow-listed, and the amount fits the cap of the agent's tier. The human admin keeps a bypass, so a lapsed certificate can never lock the funds.

How it decides

1 · Certificate registry

Once a day the attester publishes one Merkle root over every certificate that is VALID off-chain and bound to a wallet. A leaf is (agent, task type, tier, karats, expiry). Anyone can prove a leaf, which caches it in one storage slot; guards read status(agent, taskType). Tiers: 1 ≥ 12K, 2 ≥ 18K, 3 ≥ 22K. A certificate stops counting when it expires, when the attester revokes it, or when it is missing from the latest roots (SUPERSEDED).

2 · Safe guard and ERC-7579 module

KaratumSafeGuard (Safe v1.4.1 checkTransaction) and KaratumGuard7579 (validator + hook) share one policy engine: allow-listed targets mapped to task types, certificate VALID at tier ≥ minTier, per-transaction and per-day caps scaled by the tier (native and ERC-20), no delegatecall, no self-calls, no gas refunds. If roots stop arriving, the account's own fail-open / fail-closed setting decides; an expired or revoked certificate always blocks.

3 · Preflight pass

POST /v1/guard/preflight runs the exact call on an Anvil fork of the target chain, runs the account's guard on that fork, reads the agent's certificate, and answers PASS / WARN / BLOCK. On PASS it signs a 10-minute EIP-712 pass bound to the account, the call, the Safe nonce and the chain. A Safe can require it (requirePreflight). The success probability it signs is the lower bound of the agent's 95% Wilson interval of verified successes, and 0 if the simulation fails.

4 · Agents

The AgentKit provider karatum_guard preflights every transaction and sends only on PASS, through the Safe with the pass attached. The guard re-checks everything on-chain, so a stale preflight cannot let a revoked agent through.

Live demo on Base Sepolia

The Guard API is not reachable right now.

Contracts and roots

NetworkContractsLatest root

Leaves are certificates that are VALID off-chain and bound to a wallet (a build registered with its wallet, or an explicit operator binding). Preflights answered so far: 0. Preflight signer not configured.

Use it

Protect a Safe

// 1. Admin-executed Safe tx: configure the policy on KaratumSafeGuard (Base Sepolia)
guard.configure(
  { agent, admin, defaultTaskType: keccak256("karatum.task.web3"), minTier: 1,
    failOpen: false, requirePreflight: true, preflightSigner, minSuccessBps: 9000,
    txCap:    [0, 0.0001 ether, 0.0005 ether, 0.001 ether],   // wei per tx, by tier 0..3
    dailyCap: [0, 0.0003 ether, 0.0015 ether, 0.003 ether] },
  [{ target: payee, allowed: true, taskType: 0x0 }],          // allow-list
  [])                                                         // ERC-20 caps (optional)
// 2. Admin-executed Safe tx: safe.setGuard(KaratumSafeGuard)
// From now on, any transaction NOT executed by the admin must pass the guard.

Preflight a transaction

curl -s https://karatum.com/v1/guard/preflight -H 'content-type: application/json' -d '{
  "chainId": 84532,
  "agent":   "0xAGENT",
  "account": "0xSAFE",
  "tx": { "to": "0xPAYEE", "value": "400000000000000", "data": "0x" }
}'
# -> { verdict: PASS | WARN | BLOCK, successProbability, reasons, simulation, pass: { trailer, expiresAt } }
# Safe signatures = ownerSignatures ++ pass.trailer   (79 bytes, "KGP1")

AgentKit

import { AgentKit } from "@coinbase/agentkit";
import { karatumGuardActionProvider } from "@karatum/agentkit-actions";

const agentkit = await AgentKit.from({
  walletProvider,                       // Base Sepolia
  actionProviders: [karatumGuardActionProvider({ allowSend: true })],
});
// actions: guard_preflight, guarded_send_transaction (sends only on PASS), guard_status

Prove a certificate

GET /v1/guard/proof?agent=0x…&taskClass=web3 returns the leaf, epoch and Merkle proof per chain; anyone can submit it to KaratumCertRegistry.prove. Karatum proves the agents of the accounts it watches after every root.

Runbook: docs/runbooks/guard.md. Contracts: contracts/src/guard (Foundry unit tests and fork tests against the real Safe v1.4.1 on Base Sepolia).

Scope

  • Testnets only (Base Sepolia, Ethereum Sepolia). The contracts have had an internal security review, not an external audit.
  • The ERC-7579 module is covered by unit tests against a minimal 7579 account; it has not yet run on a production 7579 account.
  • The demo agent wallet is a Karatum testnet key bound to a Karatum house build for the demo; the certificate behind it is the build's real one.
  • Safe modules bypass Safe 1.4.1 transaction guards: keep modules off on agent Safes (the agent itself cannot enable one).