<!-- 0Gkit docs — prediction-market kit
     Source: https://docs.0gkit.com/kits/prediction-market
     LLM-friendly Markdown twin of the page. -->

# prediction-market

> **AI-resolved, proof-anchored prediction market.** Lifecycle: open → bet →
> resolve (via `ai-oracle`) → settle. Composes `ai-oracle` so applying
> `prediction-market` auto-applies `ai-oracle` first. Resolution receipts are
> signed by the operator key (✓ signature verified — not TEE-quote) and
> anchored to 0G Storage (or on-chain opt-in).

## What it does

The `prediction-market` kit adds a full prediction market lifecycle to your
0G app:

1. **Open** — create a market with a question and deadline.
2. **Bet** — participants place YES/NO positions.
3. **Resolve** — at deadline, the kit calls `resolveOracle` (from the composed
   `ai-oracle` lib) to get a signed, anchored AI verdict.
4. **Settle** — `resolveMarket` marks the market settled and stores the
   signed resolution receipt in 0G Storage for auditability (immutable
   content-addressed commitment). Set `OG_ANCHOR_ONCHAIN=1` to also write the
   root on-chain via `Anchor.sol`.

Because `prediction-market` declares `"composes": ["ai-oracle"]`, running
`0g add prediction-market` applies `ai-oracle` first, then the market overlay,
and merges dependencies from both kits into `package.json`.

## Compatible bases

`react-app` · `chat` · `tee-attested-api`

## Apply

```bash
# scaffold-time (applies ai-oracle automatically)
npm create 0gkit-app -- --kits prediction-market

# add to an existing project
0g add prediction-market
```

## Environment variables

Inherits all `ai-oracle` env vars, plus:

| Variable               | Example                                       | Notes                                                                   |
| ---------------------- | --------------------------------------------- | ----------------------------------------------------------------------- |
| `OG_COMPUTE_MODEL`     | `neuralmagic/Meta-Llama-3.1-70B-Instruct-FP8` | Model for resolution oracle (optional)                                  |
| `OG_PRIVATE_KEY`       | `0x...`                                       | Operator key for signing resolution receipts                            |
| `OG_RPC_URL`           | `https://evmrpc-testnet.0g.ai`                | 0G chain RPC endpoint                                                   |
| `OG_ANCHOR_ONCHAIN`    | `1`                                           | Set to `1` to commit resolution receipts on-chain (default: 0G Storage) |
| `OG_ANCHOR_ADDRESS`    | `0x...`                                       | Deployed `Anchor.sol` address — required when `OG_ANCHOR_ONCHAIN=1`     |
| `OG_STORAGE_NAMESPACE` | `prediction-market`                           | Namespace prefix for market blobs in 0G Storage                         |

## Quick start

```bash
0g add prediction-market   # composes ai-oracle — applied automatically first
```

`openMarket` / `placeBet` / `resolveMarket` drive the lifecycle over an injected
`MarketStorage`. `resolveMarket` delegates to the composed
[`ai-oracle`](/kits/ai-oracle) `resolveOracle` for the settlement answer:

```ts
import { Storage } from "@foundryprotocol/0gkit-storage";
import {
  createMarketStore,
  openMarket,
  placeBet,
  resolveMarket,
  type MarketStorage,
} from "./lib/market.js";
import { resolveOracle } from "./lib/oracle.js"; // co-located by composition

const storage = new Storage({
  privateKey: process.env.OG_PRIVATE_KEY as `0x${string}`,
  rpcUrl: process.env.OG_RPC_URL!,
});
// Content-addressed → mutable-namespace bridge (persist `roots` in production).
const roots = new Map<string, string>();
const marketStorage: MarketStorage = {
  async putBlob(ns, data) {
    const { root } = await storage.upload(new TextEncoder().encode(data));
    roots.set(ns, root);
  },
  async getBlob(ns) {
    const root = roots.get(ns);
    if (!root) return undefined;
    const bytes = await storage.download(root);
    return bytes ? new TextDecoder().decode(bytes) : undefined;
  },
};

const store = createMarketStore(marketStorage);
const market = await openMarket(store, {
  question: "Will 0G mainnet launch in 2026?",
  closesAt: Date.now() + 86_400_000,
});
await placeBet(store, {
  marketId: market.id,
  bettor: "0xYou",
  prediction: "YES",
  amount: 10,
});

// `oracleDeps` = { infer, attestor, anchor, model } — see the ai-oracle quick start.
const boundOracle = (_deps: unknown, question: string) =>
  resolveOracle(oracleDeps, question);
const { market: settled, receipt } = await resolveMarket(
  { resolveOracle: boundOracle, storage: marketStorage },
  market.id
);
console.log(settled.state, receipt.answer, receipt.commitment);
```

> **Honesty caveat:** resolution uses the composed `ai-oracle` **signed receipt**
> (operator key signs `digestJson(receipt)`, verified via `recoverSigner`) —
> **not** a TEE-quote. Settle is folded into `resolveMarket`; there is no separate
> `settleMarket`.

## Tiers

- **lib** — `lib/market.ts` (portable `Market`, `Bet`, `Resolution` types,
  `openMarket` / `placeBet` / `resolveMarket` helpers; settle is folded into
  resolve — there is no separate `settleMarket`).
- **adapters** — one per base (`app/api/markets/route.ts` for Next.js,
  `src/routes/markets.ts` for Express).
- **ui** — `app/markets/page.tsx` (market list page),
  `components/MarketBoard.tsx`, `components/CreateMarketForm.tsx`
  (React bases only).

## Composition

`prediction-market` `composes` `ai-oracle`. The engine resolves the full
closure deps-first (deduped, cycle-safe) before writing any files, so both
kits' files land in the project and both kits' `package.json` dependencies
are merged.

## Honesty note

Resolution uses `resolveOracle` from the composed `ai-oracle` lib, which
produces an **operator-signed receipt**: `digestJson(receipt)` signed via
EIP-191 personal-sign (`signMessage`); the signer is recovered with
`recoverSigner`. There is no TEE quote verification. The badge is
"✓ signature verified". The `Attestor` interface is injected so a real
TEE-quote verifier can slot in later without changing market code.
