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
- Proposers: Research thoroughly before proposing
- Challengers: Only dispute when certain proposer is wrong
- Both: Monitor dispute window timing carefully
- All: Use "not clear yet" appropriately for premature questions