0Gkitdocs↗ HomePlaygroundGitHub

ai-oracle

Signed AI answers with commitments anchored to 0G Storage (default) or on-chain. Each answer is hashed, signed by the operator key (✓ signature verified — not TEE-quote), and anchored as an immutable proof. Composes into prediction-market.

What it does

The ai-oracle kit adds a verifiable AI query endpoint to your 0G app. When a request arrives the kit:

  1. Calls @foundryprotocol/0gkit-compute to run inference against the configured model.
  2. Serialises the result into an oracle receipt ({ question, answer, answerHash, ts }).
  3. Signs the receipt with the operator key via EIP-191 personal-sign: digestJson(receipt) is hashed and signed with signMessage; the badge reads ✓ signature verified and is backed by recoverSigner — this is an operator-signed receipt, not a hardware TEE quote.
  4. Anchors the receipt to 0G Storage by default (immutable, content-addressed root = the commitment). Set OG_ANCHOR_ONCHAIN=1 to also write the root on-chain via the bundled Anchor.sol contract (@foundryprotocol/0gkit-contracts).

Compatible bases

react-app · chat · tee-attested-api · mcp-agent

Apply

# scaffold-time
npm create 0gkit-app -- --kits ai-oracle

# add to an existing project
0g add ai-oracle

Environment variables

VariableExampleNotes
OG_COMPUTE_MODELneuralmagic/Meta-Llama-3.1-70B-Instruct-FP8Model for inference (optional — provider default if omitted)
OG_PRIVATE_KEY0x...Operator key for signing receipts and 0G transactions
OG_RPC_URLhttps://evmrpc-testnet.0g.ai0G chain RPC endpoint
OG_ANCHOR_ONCHAIN1Set to 1 to commit receipts on-chain via Anchor.sol (default: 0G Storage)
OG_ANCHOR_ADDRESS0x...Deployed Anchor.sol address — required when OG_ANCHOR_ONCHAIN=1

Quick start

0g add ai-oracle

resolveOracle(deps, question) runs inference → hashes the answer → signs the receipt → anchors it. deps is injected; here is the default wiring the react-app adapter builds (compute router + signed-receipt attestor + 0G Storage anchor). The .env keys are the ones in the table above:

import { Compute } from "@foundryprotocol/0gkit-compute";
import { Storage } from "@foundryprotocol/0gkit-storage";
import { digestJson } from "@foundryprotocol/0gkit-core";
import { fromPrivateKey } from "@foundryprotocol/0gkit-wallet";
import { recoverSigner } from "@foundryprotocol/0gkit-attestation";
import { resolveOracle, type Attestor, type Anchor } from "./lib/oracle.js";

const privateKey = process.env.OG_PRIVATE_KEY as `0x${string}`;
const signer = await fromPrivateKey(privateKey);
const compute = new Compute({ signer });

const infer = {
  async infer({ prompt, model }: { prompt: string; model?: string }) {
    const r = await compute.router({
      messages: [{ role: "user" as const, content: prompt }],
      ...(model ? { model } : {}),
    });
    return { output: r.output };
  },
};

const attestor: Attestor = {
  async sign(receipt) {
    const digest = digestJson(receipt);
    return { digest, signature: await signer.signMessage({ raw: digest }) };
  },
  async verify(receipt, signed, expectedSigner) {
    const match = digestJson(receipt).toLowerCase() === signed.digest.toLowerCase();
    const recovered = await recoverSigner({
      digest: signed.digest as `0x${string}`,
      signature: signed.signature as `0x${string}`,
    });
    return {
      ok: match && recovered.toLowerCase() === expectedSigner.toLowerCase(),
      signer: recovered,
    };
  },
};

const storage = new Storage({ privateKey, rpcUrl: process.env.OG_RPC_URL! });
const anchor: Anchor = {
  async anchor(payload) {
    const bytes =
      typeof payload === "string" ? new TextEncoder().encode(payload) : payload;
    const { root } = await storage.upload(bytes);
    return { ref: root, kind: "storage" };
  },
};

const result = await resolveOracle(
  { infer, attestor, anchor, model: process.env.OG_COMPUTE_MODEL },
  "Will 0G mainnet launch in 2026?"
);
console.log(result.answer, result.answerHash, result.commitment); // { ref, kind: "storage" }

Honesty caveat: attestation is a signed receipt (operator key signs digestJson(receipt) via EIP-191), not a TEE-quote. The badge means "the expected operator signed this exact receipt" — swap the Attestor for a real TEE-quote verifier later without touching resolveOracle.

Tiers

  • liblib/oracle.ts (portable resolveOracle + OracleReceipt type), lib/anchor-abi.ts (ABI constant for the optional on-chain anchor).
  • adapters — one per base (app/api/oracle/route.ts for Next.js, src/routes/oracle.ts for Hono, src/tools/oracle.ts for MCP).
  • contractsAnchor.sol + deploy script (opt-in on-chain path only).

Honesty note

The attestation layer signs digestJson(receipt) via EIP-191 personal-sign (signMessage); verification recovers the signer via recoverSigner. There is no TEE quote verification in the current stack. The badge is always "✓ signature verified" — never "TEE attested". The Attestor interface is injected so a real TEE-quote verifier can slot in later without changing calling code.