Proposing and Disputing

Learn how to propose answers and challenge incorrect proposals on the Optimistic Oracle.

Proposing an Answer

Requirements

  • 1,000,000 $TRUTH tokens (collateral)
  • Query in Awaiting state
  • Knowledge of the correct answer

Step by Step

import { ethers } from 'ethers'

const OPTIMISTIC_ORACLE_ADDRESS = '0xA83689161DFa9d5992fBa658d3148C6f72E1419E'
const PROPOSAL_COLLATERAL = ethers.parseEther('1000000')

// 1. Approve token spending
const tokenContract = new ethers.Contract(TOKEN_ADDRESS, TOKEN_ABI, signer)
const approveTx = await tokenContract.approve(OPTIMISTIC_ORACLE_ADDRESS, PROPOSAL_COLLATERAL)
await approveTx.wait()

// 2. Propose answer
const optimisticOracle = new ethers.Contract(
  OPTIMISTIC_ORACLE_ADDRESS,
  OPTIMISTIC_ORACLE_ABI,
  signer
)

const queryId = 0 // The query you want to propose to
const selectedOptions = [0] // Index 0 = first option

const proposeTx = await optimisticOracle.proposeAnswer(queryId, selectedOptions)
await proposeTx.wait()

Proposal Options

Single Option:

const selectedOptions = [1] // Propose option at index 1

Multiple Options:

const selectedOptions = [0, 2] // Propose options 0 AND 2

No Correct Choice:

const selectedOptions = [] // Empty array = no option is correct

Important Notes

  • You cannot propose option 255 ("not clear yet")
  • This option is reserved for dispute challenges
  • Once proposed, the 1.5 hour dispute window begins

Disputing a Proposal

When to Dispute

  • Proposer selected wrong option(s)
  • Answer is not yet determinable
  • Evidence contradicts the proposal

Requirements

  • 1,000,000 $TRUTH tokens (dispute collateral)
  • Query in Proposed state
  • Within 1.5 hour dispute window

How to Dispute

const DISPUTE_COLLATERAL = ethers.parseEther('1000000')

// 1. Approve collateral
const approveTx = await tokenContract.approve(OPTIMISTIC_ORACLE_ADDRESS, DISPUTE_COLLATERAL)
await approveTx.wait()

// 2. Dispute the proposal
const queryId = 0
const disputeAsNotClear = false // Set to true if answer isn't clear yet

const disputeTx = await optimisticOracle.dispute(queryId, disputeAsNotClear)
await disputeTx.wait()

Dispute Options

Standard Dispute:

const disputeAsNotClear = false
// Escalates to main oracle for final answer
// Main oracle will choose from original options

"Not Clear Yet" Dispute:

const disputeAsNotClear = true
// Tells main oracle answer isn't determinable yet
// If main oracle agrees (chooses "Not clear yet"), query resets to awaiting

What Happens After Dispute?

1. Main Oracle Query Created

  • Automatically funded with 100,000 tokens
  • Same question and options
  • Plus one additional option: "Not clear yet" (added as the last option with label)

2. Community Voting

  • Main oracle users vote on the correct answer
  • Full voting period and tie-breaking mechanisms apply

3. Resolution Outcomes

Proposer Was Correct:

  • Proposer gets: 1M + 900k from challenger + 20k reward
  • 10k burned to 0xdead
  • Challenger loses collateral

Challenger Was Correct:

  • Challenger gets: 1M + 900k from proposer + 20k reward
  • 10k burned to 0xdead
  • Proposer loses collateral

Not Clear Yet (Last Option):

  • Challenger gets: 1M + 900k from proposer = 1,900,000 (no 20k reward - not final resolution)
  • Proposer loses collateral (should not have proposed prematurely)
  • 30k creation deposit stays in contract for final resolution
  • Query returns to awaiting state
  • Can be proposed to again when answer becomes clear
  • Final resolver will get 20k reward, and 10k will be burned

Checking Dispute Window

const queryId = 0

// Check if you can still dispute
const canDispute = await optimisticOracle.canDispute(queryId)
console.log('Can dispute:', canDispute)

// Check blocks remaining
const blocksRemaining = await optimisticOracle.getDisputeWindowRemaining(queryId)
console.log('Blocks remaining:', blocksRemaining.toString())

// Calculate time remaining (0.75s per block on BSC)
const secondsRemaining = Number(blocksRemaining) * 0.75
const minutesRemaining = secondsRemaining / 60
console.log('Minutes remaining:', minutesRemaining.toFixed(1))

Economic Risks and Rewards

For Proposers

  • Risk: Lose 900k tokens if wrong
  • Reward: Gain 920k tokens if correct (and undisputed or disputed)
  • Best Practice: Only propose when confident

For Challengers

  • Risk: Lose 900k tokens if proposer was correct
  • Reward: Gain 920k tokens if proposer was wrong
  • Best Practice: Only dispute clear mistakes

For Query Creators

  • Guaranteed: Always get 10k tokens back
  • No additional risk or reward based on outcome

Resolving After Dispute

Anyone can call resolution once the main oracle resolves:

const queryId = 0
const resolveTx = await optimisticOracle.resolveDisputed(queryId)
await resolveTx.wait()

Or for undisputed queries after the window closes:

const resolveTx = await optimisticOracle.resolveUndisputed(queryId)
await resolveTx.wait()

Best Practices

  1. Proposers: Research thoroughly before proposing
  2. Challengers: Only dispute when certain proposer is wrong
  3. Both: Monitor dispute window timing carefully
  4. All: Use "not clear yet" appropriately for premature questions