Skip to main content

Question templates

The oracle is only as good as the questions it answers. The single most common failure mode in optimistic oracles isn't bugs in the contracts — it's ambiguous questions where reasonable people disagree about the right answer. Disputes pile up, controversies erupt, trust erodes.

This page is the practical guide to writing questions that don't break.

The three properties a good question has

import {DocFeatures, DocFeature} from '@site/src/components/docs/DocFeatures';

Exactly one place to look for the answer. If multiple sources exist, pin which one is authoritative. Date, time, and timezone. Not "by next month". "By 23:59 UTC on 2026-03-15". What happens if the source is unreachable? If the event is cancelled? If the answer is ambiguous? Specify before the dispute.

Anti-patterns to avoid

❌ "Will Bitcoin reach $200k?"

What's wrong:

  • No source (CoinMarketCap? Coinbase? Spot or futures?)
  • No deadline
  • "Reach" is ambiguous — touch once, sustain for an hour, close above?

❌ "Did the team ship the milestone?"

What's wrong:

  • No source — who decides what "shipped" means?
  • No deadline
  • Subjective threshold

❌ "Was the protocol hacked?"

What's wrong:

  • No source
  • No definition of "hacked" (UI exploit? Bug bounty? Loss > $X?)
  • No timeframe

Good patterns

Spot-price threshold

"Did the BTC/USDT spot price on Binance close at or above $200,000.00 USD at 00:00:00 UTC on 2026-12-31, as reported by Binance's official kline API at endpoint klines?symbol=BTCUSDT&interval=1d?"

Why it works:

  • Source: Binance kline API, specific endpoint
  • Asset pair: BTC/USDT explicitly
  • Time: 00:00 UTC, specific date
  • Boundary: "at or above" — inclusive
  • Field: close price on the daily kline

Fallback for source unavailability: include a secondary like "or if Binance API is unreachable for ≥24 hours, the equivalent value from CoinGecko at the same UTC timestamp".

Scheduled-event happened

"Did the official scoreboard at worldcup.example.com/match/123 show the final score as a victory for team Atlas (any margin) as of 23:59 UTC on the day of the match (2026-07-15)?"

Why it works:

  • Source: specific URL
  • Definition: "victory" = positive goal differential (any margin)
  • Time bound: end of match day, UTC

Fallback: "if the scoreboard does not display a final result by 24h after the scheduled match time, resolves NO".

Signed-document attestation

"Does the PDF at https://escrow.example/m1-report.pdf with SHA-256 abc...123 contain a valid GPG signature from key xyz... (fingerprint documented at gov.example/signing-keys) and a recommendation field equal to approved, as of 23:59 UTC on 2026-04-15?"

Why it works:

  • Source: specific URL + content hash
  • Signer: specific public key
  • Field: specific JSON path inside the document
  • Deadline: explicit

Public-registry lookup

"Does the public registry at https://reg.example.gov/cert/X show that Certificate X was issued to entity Acme Corp Ltd. (registration number 12345) before 00:00 UTC on 2026-06-30?"

Why it works:

  • Source: official government registry, specific URL
  • Entity: full legal name + registration number (defends against name aliases)
  • Date: explicit deadline

Fallback: "if the registry is unreachable from the gov.example domain for ≥72 hours preceding the deadline, the assertion is cancelled and bonds refunded".

Specific clauses worth including

Timezone

Always specify timezone. UTC by default. "23:59 UTC" not "midnight". Especially important for global events where "the day" depends on where the reader sits.

Source availability fallback

Sources go down. The most common dispute trigger in parametric insurance is "the source was unreachable at the resolution moment". Pre-specify:

"If primary-source.com is unreachable for ≥24h preceding the deadline, the answer is determined from secondary-source.com. If both are unreachable, the assertion is cancelled and bonds refunded."

Event cancellation

If the question references a scheduled event (sports match, election, launch), specify what happens if the event is cancelled / postponed:

"If the match is officially cancelled by tournament authority, resolves NO. If the match is rescheduled within 14 days of the original date, the question waits for the rescheduled outcome."

Reorgs / rollbacks

For blockchain-data questions, specify reorg tolerance:

"Confirmation requires the transaction to be at least 64 blocks deep in the chain at the resolution moment. If a reorg removes the transaction before the resolution moment, resolves NO."

Rounding / precision

For numeric thresholds, specify how comparison handles edge cases:

"Equality counts as YES (close ≥ $200,000.00). Rounding follows the source's native precision; values are not re-rounded by the oracle."

Question template checklist

Before deploying an assertion, your question should have:

  • Exact source URL or endpoint (not just "the official site")
  • Specific identifier (transaction hash, registry ID, document hash, entity name + registration number)
  • Deadline with timezone (e.g., "23:59 UTC on YYYY-MM-DD")
  • Boundary definition ("at or above", "strictly greater than", "any non-zero")
  • Source-unavailable fallback rule
  • Cancellation / postponement rule (if scheduled event)
  • Reorg / rollback tolerance (if blockchain data)
  • Field path inside the source (specific JSON key, specific HTML element, specific kline column)

If any of these is missing, the question will get disputed eventually.

The "would a smart adversary disagree?" test

After drafting your question, do this mental exercise:

Imagine an adversary who wants the opposite answer to yours. They will read every word looking for an interpretation that favors them. Can they point to anything ambiguous?

If yes, fix it. Add a clarifying clause. Pick a more specific source. Tighten the deadline.

If you can't satisfy this test, the question is too subjective for an optimistic oracle. Use a curated committee with explicit authority over this question class — or don't put it on-chain.

Templates as code

For consumer contracts that auto-generate many similar questions (a prediction-market platform, a bridge, an insurance pool), bake the question template into the consumer contract itself:

fun buildQuestion(eventId: uint64, deadline: uint32): cell {
return beginCell()
.storeStringTail('Did event ')
.storeUint(eventId, 64)
.storeStringTail(' confirm per source X by ')
.storeUint(deadline, 32)
.storeStringTail(' UTC, with reorg-tolerance 64 blocks?')
.endCell();
}

This guarantees every assertion the consumer spawns inherits the same unambiguous template. No room for human error in question-writing.

Where next