Skip to main content
PredictStreetOracle is the only contract authorised to call ConditionalTokens.reportPayouts for PredictStreet markets.

Key constants (testnet defaults)

ParameterDefaultSOP reference
bondAmount10 USDC§8.1
challengeWindow7200s (2 hours)§8.1
rewardAmount0 USDC§8.3
revenueWalletSet at deploy§8.3
emergencyClearTimelock604800s (7 days)§8.4

Write surface (oracle-service is the sole caller)

FunctionPurpose
proposeOutcome(questionId, payouts[])Start challenge window
finalizeOutcome(questionId)After window, call reportPayouts
resolveChallengeConfirm(questionId)On dispute: confirm original
resolveChallengeOverride(questionId, newPayouts[])On dispute: corrected
voidMarket(questionId)CO+CTO joint: all collateral refunded
voidUnproposedMarket(questionId, outcomeSlotCount)Void before proposeOutcome
markDelayed(questionId) / undelay(questionId)Pause-while-waiting
initiateProposalClear(questionId)Start 7d timelock for emergency clear
executeProposalClear(questionId)Execute after 7d

Read surface (anyone)

FunctionReturns
getProposal(questionId)(questionId, payouts, proposedAt, bondSnapshot)
getChallenge(questionId)(challenger, bondSnapshot, note)
getState(questionId)uint8 state enum
isInChallengeWindow(questionId)bool

Events

event OutcomeProposed(uint64 seq, bytes32 indexed questionId, uint256[] payouts);
event OutcomeChallenged(uint64 seq, bytes32 indexed questionId, address challenger, uint256 bondAmount);
event ChallengeResolvedConfirm(uint64 seq, bytes32 indexed questionId);
event ChallengeResolvedOverride(uint64 seq, bytes32 indexed questionId, uint256[] newPayouts);
event MarketVoided(uint64 seq, bytes32 indexed questionId);
event MarketDelayed(uint64 seq, bytes32 indexed questionId, bool delayed);
event BondAmountSet(uint64 seq, uint256 bondAmount);
event ChallengeWindowSet(uint64 seq, uint256 challengeWindow);
event ProposalClearInitiated(uint64 seq, bytes32 indexed questionId, uint256 unlockAt);
event ProposalClearExecuted(uint64 seq, bytes32 indexed questionId);

Challenging from a partner integration

POST /api/oracle/challenges
# Retail-only surface (app.predictstreet.io) — oracle challenges
# require a user-signed bond. Not exposed via partner API today.
{ "marketId": "...", "reason": "50-char-min free text" }

Direct on-chain

import { Contract, parseUnits } from 'ethers';

const oracle = new Contract(ORACLE_ADDRESS, ORACLE_ABI, signer);
await usdc.approve(ORACLE_ADDRESS, parseUnits('10', 6));
const bondSnapshot = await oracle.bondAmount();
const note = keccak256(toUtf8Bytes('your-free-text-reason'));
await oracle.challengeOutcome(questionId, bondSnapshot, note);

Source

0x24731ADFe7FB28E037c04D71f89f52974Ae76ee1 on Blockscout (testnet).