Skip to content

Repository files navigation

opal-resolver

The trusted LLM resolver service for Opal — the off-chain half of ADR-0002.

A single long-running Bun worker that:

  1. Scans the Opal program for unresolved LlmResolutionRound PDAs (getProgramAccounts, filtered on the account discriminator + outcome byte 255 at offset 72; account size 98 bytes). Chain state is the work queue — there is no database.
  2. Reads the disputed assertion's statement and calls Gemini to judge it against its Resolution Spec. Google-Search grounding (live web) is optional via GEMINI_GROUNDING — off by default because it requires a paid Gemini tier.
  3. Submits the verdict on-chain via submit_llm_resolution, signed by the resolver keypair (ProtocolConfig.resolver). Verdicts are True (0), False (1), or Unresolvable (3) — the program rejects TooEarly (2) per ADR-0005.

Idempotency is on-chain: a posted verdict drops out of the next scan, and the program's PendingLLM guard rejects any second submission. Chain state is both the queue and the dedup.

Run

bun install
cp .env.example .env   # fill in GEMINI_API_KEY, RPC_URL, PROGRAM_ID, RESOLVER_KEYPAIR_PATH
solana-keygen new -o keys/resolver.keypair.json   # resolver signing key; must match ProtocolConfig.resolver on-chain
bun start

GEMINI_GROUNDING=false (the default) resolves from the model's training knowledge with no live web access; set it true only on a paid Gemini tier (grounded calls 429 on the free tier).

Flags:

  • --manual <assertion_pubkey> <outcome_code> — post one verdict by hand and exit (demo fallback).
  • --once — single scan pass instead of the 10s loop.

Test

bun run test    # unit: verdict parsing, injection screening, discriminators (no external deps)
bun run e2e     # end-to-end against the dummy anchor program on a local validator

bun run test needs nothing external. The e2e runs against test-program/ — a minimal Anchor 1.1.2 program with the same 98-byte round layout as Opal, so the full scan → resolve → submit loop is proven without touching the real program. It requires the Solana CLI (solana-test-validator) and Anchor 1.1.2, and the dummy program built first:

cd test-program && anchor build && cd ..
bun run e2e

Note: plain bun test (no script) runs both suites, so it carries the same e2e prerequisites. Use bun run test for the dependency-free unit suite.

Running it

For a demo or a one-off, just run it locally — bun start (see Run); no container needed.

For persistent operation it needs to stay up whenever a dispute exists (an unresolved assertion has no on-chain timeout), so long-term it runs as a single always-on worker. The Dockerfile packages exactly that — no HTTP surface, two secrets (resolver keypair + Gemini key) injected via env:

docker build -t opal-resolver .
docker run --env-file .env opal-resolver

Any container host works (Fly.io, Railway, a small VPS); restart-on-crash comes from the host's restart policy.

Security notes

  • The resolver key is a hot key. On-chain it can only post challengeable verdicts — it is deliberately not the protocol authority.
  • Statements are untrusted input: they are wrapped in tags, screened for prompt injection, and the model is instructed to return Unresolvable on any attempt to steer it.
  • Never commit .env or anything under keys/.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages