IOptimisticOracle Interface

Complete Solidity interface for integrating with the OptimisticOracle contract on BSC Mainnet.

Contract Address

OptimisticOracle: 0xA83689161DFa9d5992fBa658d3148C6f72E1419E (BSC Mainnet)

View on BSCScan

Overview

The OptimisticOracle provides fast, low-cost oracle resolution through an optimistic mechanism with dispute escalation to the main DecentralizedOracle.

Key Features:

  • Fast Resolution: Queries resolve in ~1.5 hours if undisputed
  • Economic Security: 1M token collateral for proposals and disputes
  • Dispute Escalation: Automatic escalation to DecentralizedOracle when disputed
  • "Not Clear Yet" Handling: Queries can be reset if resolution is premature

Query Lifecycle:

Awaiting → Proposed → [Disputed →] Resolved
           (1.5h)      (escalate)

Economic Parameters

ParameterValueDescription
CREATION_COST30,000 tokensCost to create a query (20k reward, 10k burned)
PROPOSAL_COLLATERAL1,000,000 tokensCollateral to propose an answer
DISPUTE_COLLATERAL1,000,000 tokensCollateral to dispute a proposal
DISPUTE_WINDOW7,200 blocks~1.5 hours at 0.75s/block (BSC)
MAIN_ORACLE_FUNDING100,000 tokensDeducted from loser's collateral
PROPOSER_REWARD20,000 tokensReward for correct resolution

Complete Interface

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title IOptimisticOracle
 * @notice Interface for the OptimisticOracle contract - a permissionless optimistic oracle with dispute mechanism
 * @dev Deployed at: 0xA83689161DFa9d5992fBa658d3148C6f72E1419E (BSC Mainnet)
 *
 * This oracle allows fast, low-cost resolution of queries through an optimistic mechanism:
 * 1. Anyone can create a query with string options (pays 30k tokens)
 * 2. Anyone can propose an answer (locks 1M tokens as collateral)
 * 3. Anyone can dispute within ~1.5 hours (locks 1M tokens)
 * 4. If disputed, escalates to main DecentralizedOracle for resolution
 * 5. Winner receives collateral + 900k from loser + 20k reward
 *
 * Query lifecycle: Awaiting -> Proposed -> [Disputed ->] Resolved
 *
 * Special handling:
 * - Options use standard 0-based indexing (0 to N-1)
 * - Empty array means "No correct choice"
 * - When disputed, main oracle adds "Not clear yet" as option N
 * - If resolved as "Not clear yet", query resets to Awaiting state
 *
 * @custom:see contracts/OptimisticOracle.sol
 */
interface IOptimisticOracle {

    // ============ Enums ============

    /**
     * @notice Possible states for an optimistic query
     * @param Awaiting Waiting for someone to propose an answer
     * @param Proposed Answer proposed, dispute window open
     * @param Disputed Answer disputed, awaiting main oracle resolution
     * @param Resolved Final answer determined
     */
    enum QueryState { Awaiting, Proposed, Disputed, Resolved }

    // ============ Events ============

    /**
     * @notice Emitted when a new optimistic query is created
     * @param queryId The unique identifier for the query
     * @param creator Address that created the query
     * @param question The question text
     * @param optionsCount Number of options provided
     */
    event OptimisticQueryCreated(uint256 indexed queryId, address indexed creator, string question, uint256 optionsCount);

    /**
     * @notice Emitted when an answer is proposed for a query
     * @param queryId The query identifier
     * @param proposer Address that proposed the answer
     * @param answer Array of option indices (empty for "no correct choice")
     */
    event AnswerProposed(uint256 indexed queryId, address indexed proposer, uint8[] answer);

    /**
     * @notice Emitted when a proposed answer is disputed
     * @param queryId The query identifier
     * @param challenger Address that disputed the answer
     * @param mainOracleQueryId The ID of the escalated query in the main oracle
     * @param asNotClear True if disputing as "not clear yet"
     */
    event AnswerDisputed(uint256 indexed queryId, address indexed challenger, uint256 mainOracleQueryId, bool asNotClear);

    /**
     * @notice Emitted when a query is resolved
     * @param queryId The query identifier
     * @param finalAnswer Array of winning option indices
     * @param isNotClearYet True if resolved as "not clear yet" (query reset to Awaiting)
     */
    event QueryResolved(uint256 indexed queryId, uint8[] finalAnswer, bool isNotClearYet);

    /**
     * @notice Emitted when a query is reset to Awaiting state (after "not clear yet" resolution)
     * @param queryId The query identifier
     */
    event QueryResetToAwaiting(uint256 indexed queryId);

    /**
     * @notice Emitted when rewards are claimed by a participant
     * @param queryId The query identifier
     * @param recipient Address receiving the rewards
     * @param amount Amount of tokens received
     */
    event RewardsClaimed(uint256 indexed queryId, address indexed recipient, uint256 amount);

    // ============ Constants ============

    /**
     * @notice Cost to create a new query (30,000 tokens)
     * @dev Depositor gets 10k burned, winner gets 20k as reward
     */
    function CREATION_COST() external view returns (uint256);

    /**
     * @notice Collateral required to propose an answer (1,000,000 tokens)
     */
    function PROPOSAL_COLLATERAL() external view returns (uint256);

    /**
     * @notice Collateral required to dispute an answer (1,000,000 tokens)
     */
    function DISPUTE_COLLATERAL() external view returns (uint256);

    /**
     * @notice Dispute window duration in blocks (~1.5 hours at 0.75s/block)
     */
    function DISPUTE_WINDOW() external view returns (uint256);

    /**
     * @notice Reward paid to final resolver from creation deposit (20,000 tokens)
     */
    function PROPOSER_REWARD() external view returns (uint256);

    /**
     * @notice Amount deducted from loser's collateral to fund main oracle query (100,000 tokens)
     */
    function MAIN_ORACLE_FUNDING() external view returns (uint256);

    /**
     * @notice Maximum regular option index (254)
     * @dev Index 255 is reserved for internal use
     */
    function MAX_REGULAR_OPTION() external view returns (uint8);

    /**
     * @notice Burn address for unused creation deposit (0x000000000000000000000000000000000000dEaD)
     */
    function BURN_ADDRESS() external view returns (address);

    // ============ State Variables ============

    /**
     * @notice Total number of queries created
     */
    function queryCount() external view returns (uint256);

    /**
     * @notice The ERC20 token used for collateral and rewards
     * @return Address of the ERC20 token contract
     */
    function token() external view returns (address);

    /**
     * @notice The main DecentralizedOracle used for dispute resolution
     * @return Address of the DecentralizedOracle contract
     */
    function mainOracle() external view returns (address);

    // ============ Core Functions ============

    /**
     * @notice Create a new optimistic query with string options
     * @dev Requires approval for CREATION_COST tokens
     * @param question The question to ask
     * @param options Array of option strings (2-254 options required)
     * @return queryId The unique identifier for the created query
     */
    function createQuery(string memory question, string[] memory options) external returns (uint256);

    /**
     * @notice Propose an answer to a query
     * @dev Requires approval for PROPOSAL_COLLATERAL tokens
     * @dev Query must be in Awaiting state
     * @param queryId The query ID
     * @param selectedOptions Array of option indices (can be empty for "no correct choice")
     */
    function proposeAnswer(uint256 queryId, uint8[] memory selectedOptions) external;

    /**
     * @notice Dispute a proposed answer
     * @dev Requires approval for DISPUTE_COLLATERAL tokens
     * @dev Query must be in Proposed state and within dispute window
     * @dev Escalates to main oracle with "Not clear yet" added as option N
     * @param queryId The query ID
     * @param disputeAsNotClear If true, dispute as "not clear yet"
     */
    function dispute(uint256 queryId, bool disputeAsNotClear) external;

    /**
     * @notice Resolve a query after dispute window passes without dispute
     * @dev Query must be in Proposed state and dispute window must be closed
     * @dev Proposer receives collateral + 20k reward, 10k burned
     * @param queryId The query ID
     */
    function resolveUndisputed(uint256 queryId) external;

    /**
     * @notice Resolve a disputed query after main oracle resolves
     * @dev Query must be in Disputed state and main oracle must be resolved
     * @dev If "not clear yet", challenger compensated, query reset to Awaiting
     * @dev Otherwise, winner receives collateral + 900k from loser + 20k reward
     * @param queryId The query ID
     */
    function resolveDisputed(uint256 queryId) external;

    // ============ View Functions ============

    /**
     * @notice Get the answer for a resolved query
     * @dev Reverts if query is not resolved
     * @param queryId The query ID
     * @return answer Array of option indices (can be empty for "no correct choice")
     */
    function getAnswer(uint256 queryId) external view returns (uint8[] memory);

    /**
     * @notice Get the current state of a query
     * @param queryId The query ID
     * @return state The current state (Awaiting, Proposed, Disputed, or Resolved)
     */
    function getQueryState(uint256 queryId) external view returns (QueryState);

    /**
     * @notice Get full details for a query
     * @param queryId The query ID
     * @return creator Address that created the query
     * @return question The question text
     * @return options Array of option strings
     * @return createdAt Block timestamp when created
     * @return state Current query state
     * @return proposer Address that proposed answer (if any)
     * @return proposedAnswer Proposed option indices
     * @return proposalBlock Block number when proposed
     * @return disputed Whether the query has been disputed
     * @return challenger Address that disputed (if any)
     * @return mainOracleQueryId Main oracle query ID (if disputed)
     * @return resolved Whether the query is resolved
     * @return finalAnswer Final winning option indices
     * @return isNotClearYet Whether resolved as "not clear yet"
     */
    function getQueryDetails(uint256 queryId) external view returns (
        address creator,
        string memory question,
        string[] memory options,
        uint256 createdAt,
        QueryState state,
        address proposer,
        uint8[] memory proposedAnswer,
        uint256 proposalBlock,
        bool disputed,
        address challenger,
        uint256 mainOracleQueryId,
        bool resolved,
        uint8[] memory finalAnswer,
        bool isNotClearYet
    );

    /**
     * @notice Get remaining blocks in dispute window
     * @param queryId The query ID
     * @return remaining Blocks remaining (0 if window closed or not applicable)
     */
    function getDisputeWindowRemaining(uint256 queryId) external view returns (uint256);

    /**
     * @notice Check if a query can currently be disputed
     * @param queryId The query ID
     * @return canDispute True if query is in Proposed state and within dispute window
     */
    function canDispute(uint256 queryId) external view returns (bool);

    /**
     * @notice Get paginated list of queries filtered by state
     * @param state Filter by this state
     * @param offset Starting index in the filtered results
     * @param limit Maximum number of results to return
     * @return queryIds Array of query IDs matching the criteria
     */
    function getQueriesByState(QueryState state, uint256 offset, uint256 limit)
        external
        view
        returns (uint256[] memory queryIds);
}

Usage in Your Contract

Copy the interface above into your project, or import it directly:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./IOptimisticOracle.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract MyContract {
    IOptimisticOracle public immutable oracle;
    IERC20 public immutable token;

    constructor(address _oracle, address _token) {
        oracle = IOptimisticOracle(_oracle);
        token = IERC20(_token);

        // Approve unlimited spending for convenience
        token.approve(_oracle, type(uint256).max);
    }

    function createQuery(
        string calldata question,
        string[] calldata options
    ) external returns (uint256) {
        // Ensure contract has 30k tokens
        require(token.balanceOf(address(this)) >= oracle.CREATION_COST(), "Insufficient balance");

        return oracle.createQuery(question, options);
    }
}

See Also

Source Code

The canonical source code for this interface is located at:

Back to Interfaces Overview | Documentation Home