IDecentralizedOracle Interface

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

Contract Address

DecentralizedOracle: 0xFA4595F636887CA28FCA3260486e44fdcc8c8A71 (BSC Mainnet)

View on BSCScan

Overview

The DecentralizedOracle is the main oracle contract for FarmTruth, using token-weighted voting with tie-breaking mechanisms and automated state management. It serves as the final arbiter for disputed OptimisticOracle queries.

Key Features:

  • Token-Weighted Voting: Vote power proportional to token stake
  • Tie-Breaking: Automatic period extensions when tied
  • Inactivity Slashing: Creator deposits slashed if no votes after ~18 hours
  • Flexible Options: Support for 2-255 voting options
  • JSON Metadata: Rich metadata support for query context

Economic Parameters

Parameters are controlled by the Governance contract:

ParameterDefault ValueDescription
proposalCreationDeposit100,000 tokensRequired deposit to create a query
votingPeriod115,200 blocks~1 day voting period
tieExtensionPeriod28,800 blocks~6 hours extension for ties
quorumPercentage10%Minimum participation for governance

Complete Interface

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

import "./IGovernance.sol";

/**
 * @title IDecentralizedOracle
 * @notice Interface for the DecentralizedOracle contract
 * @dev Deployed at: 0xFA4595F636887CA28FCA3260486e44fdcc8c8A71 (BSC Mainnet)
 *
 * This is the main oracle contract for FarmTruth, using token-weighted voting
 * with tie-breaking mechanisms and automated state management.
 *
 * @custom:see contracts/FarmTruth.sol
 */
interface IDecentralizedOracle {

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

    /**
     * @notice Emitted when a new query is created
     * @param queryId The unique identifier for the query
     * @param creator Address that created the query
     * @param question The question text
     * @param totalOptions Number of voting options
     * @param startBlock Block when voting starts
     */
    event QueryCreated(
        uint256 indexed queryId,
        address indexed creator,
        string question,
        uint8 totalOptions,
        uint256 startBlock
    );

    /**
     * @notice Emitted when a vote is cast on a query
     * @param queryId The query identifier
     * @param voter Address that cast the vote
     * @param answerHash Hash of the selected answer
     * @param selectedOptions Array of option indices voted for
     * @param collateral Amount of tokens staked
     */
    event VoteCast(uint256 indexed queryId, address indexed voter, bytes32 answerHash, uint8[] selectedOptions, uint256 collateral);

    /**
     * @notice Emitted when a query is resolved
     * @param queryId The query identifier
     * @param winningAnswerHash Hash of the winning answer
     * @param winningOptions Array of winning option indices
     * @param totalPot Total reward pool for winners
     */
    event QueryResolved(uint256 indexed queryId, bytes32 winningAnswerHash, uint8[] winningOptions, uint256 totalPot);

    /**
     * @notice Emitted when voting period is extended due to a tie
     * @param queryId The query identifier
     * @param newEndBlock New end block after extension
     * @param uniqueWinners Number of tied winners
     */
    event VotingExtended(uint256 indexed queryId, uint256 newEndBlock, uint256 uniqueWinners);

    /**
     * @notice Emitted when a voter claims their rewards
     * @param queryId The query identifier
     * @param voter Address receiving rewards
     * @param reward Amount of tokens received
     */
    event RewardsClaimed(uint256 indexed queryId, address indexed voter, uint256 reward);

    /**
     * @notice Emitted when a query creator's deposit is slashed for inactivity
     * @param queryId The query identifier
     * @param creator Address of query creator
     * @param amount Amount slashed
     */
    event QuerySlashed(uint256 indexed queryId, address indexed creator, uint256 amount);

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

    /**
     * @notice Maximum number of options allowed per query
     */
    function MAX_OPTIONS() external view returns (uint8);

    /**
     * @notice Minimum number of options required per query
     */
    function MIN_OPTIONS() external view returns (uint8);

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

    /**
     * @notice Reference to the Governance contract
     */
    function governance() external view returns (IGovernance);

    /**
     * @notice Threshold for considering a query inactive (default: 86,400 blocks ~18 hours)
     */
    function inactivityThreshold() external view returns (uint256);

    /**
     * @notice Total number of votes cast across all queries
     */
    function totalVotes() external view returns (uint256);

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

    /**
     * @notice Create a new oracle query
     * @dev Requires approval for proposalCreationDeposit tokens
     * @param startBlock Block number when voting should start (auto-adjusted if in past)
     * @param question The question to ask
     * @param metadata JSON metadata with additional info (e.g., options array)
     * @param totalOptions Number of voting options (2-255)
     * @return queryId The unique identifier for the created query
     */
    function createQuery(
        uint256 startBlock,
        string memory question,
        string memory metadata,
        uint8 totalOptions
    ) external returns (uint256);

    /**
     * @notice Cast a vote on an active query
     * @dev Requires token approval for collateral amount
     * @param queryId The query to vote on
     * @param selectedOptions Array of option indices to vote for
     * @param collateral Amount of tokens to stake on this vote
     */
    function vote(
        uint256 queryId,
        uint8[] memory selectedOptions,
        uint256 collateral
    ) external;

    /**
     * @notice Resolve a query after voting period ends
     * @dev Can be called by anyone once conditions are met
     * @param queryId The query to resolve
     */
    function resolveQuery(uint256 queryId) external;

    /**
     * @notice Claim rewards for a winning vote
     * @dev Only winners can claim, proportional to their stake
     * @param queryId The query to claim rewards from
     */
    function claimReward(uint256 queryId) external;

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

    /**
     * @notice Get comprehensive details for a query
     * @param queryId The query identifier
     * @return creator Address that created the query
     * @return startBlock Block when voting starts
     * @return originalEndBlock Original end block
     * @return currentEndBlock Current end block (may be extended)
     * @return question The question text
     * @return metadata JSON metadata string
     * @return totalOptions Number of voting options
     * @return resolved Whether query is resolved
     * @return winningOptions Array of winning option indices
     * @return totalCollateral Total tokens staked
     * @return totalWinningCollateral Tokens staked on winning answer
     * @return totalPot Total reward pool
     * @return createdAt Timestamp when created
     * @return lastVoteBlock Block of most recent vote
     * @return inTieExtension Whether in tie extension period
     * @return canBeResolved Whether query can currently be resolved
     */
    function getQueryDetails(uint256 queryId) external view returns (
        address creator,
        uint256 startBlock,
        uint256 originalEndBlock,
        uint256 currentEndBlock,
        string memory question,
        string memory metadata,
        uint8 totalOptions,
        bool resolved,
        uint8[] memory winningOptions,
        uint256 totalCollateral,
        uint256 totalWinningCollateral,
        uint256 totalPot,
        uint256 createdAt,
        uint256 lastVoteBlock,
        bool inTieExtension,
        bool canBeResolved
    );
}

Usage in Your Contract

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

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

contract MyOracleIntegration {
    IDecentralizedOracle public immutable oracle;
    IERC20 public immutable token;

    constructor(address _oracle) {
        oracle = IDecentralizedOracle(_oracle);

        // Get token address from governance
        IGovernance governance = oracle.governance();
        token = governance.governanceToken();

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

    /// @notice Create a query with JSON metadata
    function createQueryWithMetadata(
        uint256 startBlock,
        string calldata question,
        string[] calldata options
    ) external returns (uint256) {
        // Build JSON metadata
        string memory metadata = string(abi.encodePacked(
            '{"options":["',
            options[0],
            '","',
            options[1],
            '"]}'
        ));

        return oracle.createQuery(
            startBlock,
            question,
            metadata,
            uint8(options.length)
        );
    }

    /// @notice Vote on a query
    function voteOnQuery(
        uint256 queryId,
        uint8 optionIndex,
        uint256 collateral
    ) external {
        uint8[] memory selectedOptions = new uint8[](1);
        selectedOptions[0] = optionIndex;

        oracle.vote(queryId, selectedOptions, collateral);
    }

    /// @notice Check if query can be resolved
    function checkResolvable(uint256 queryId) external view returns (bool) {
        (
            ,,,,,,,, // Skip first 8 fields
            ,,,,,, // Skip next 6 fields
            bool canBeResolved
        ) = oracle.getQueryDetails(queryId);

        return canBeResolved;
    }
}

Query States

Queries progress through different states managed by EnumerableSets:

  1. Pending: Created but voting hasn't started yet
  2. Active: Currently accepting votes
  3. Past: Resolved or expired

Tie-Breaking Mechanism

When a query resolves with multiple answers having equal top weight:

  1. Voting period extends by tieExtensionPeriod (~6 hours)
  2. Additional votes can break the tie
  3. Extension can repeat multiple times if ties persist
  4. Eventually resolves with the winning answer(s)

Inactivity Slashing

If a query receives no votes within inactivityThreshold (~18 hours):

  • Anyone can call slashInactiveQuery(queryId)
  • Creator's deposit is burned
  • Query is marked as resolved with no winner

See Also

Source Code

The canonical source code for this interface is located at:

Back to Interfaces Overview | Documentation Home