Solidity: Resolve a Query

Finalize a query after the voting period ends. The oracle selects the highest‑weight answer (by total collateral). If top answers tie, the contract extends the voting window and reverts; retry after the extension.

Requirements:

  • block.number > currentEndBlock
  • A single highest-weight answer exists (no tie)

Minimal interface

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

interface IOracleResolve {
    function resolveQuery(uint256 queryId) external;
}

Resolve with try/catch helper

Because resolveQuery reverts when it’s too early or a tie is detected, wrap it to return a boolean outcome.

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

interface IOracleResolve {
    function resolveQuery(uint256) external;
}

contract OracleResolveHelper {
    IOracleResolve public immutable oracle;

    constructor(address oracle_) {
        oracle = IOracleResolve(oracle_);
    }

    /// @notice Attempt to resolve. Returns false if too early or a tie extends voting.
    function tryResolve(uint256 queryId) external returns (bool) {
        try this._resolve(queryId) {
            return true;
        } catch {
            return false;
        }
    }

    function _resolve(uint256 queryId) external {
        oracle.resolveQuery(queryId);
    }
}

Readiness checks (off-chain friendly)

Before calling resolve on-chain, off-chain systems can check currentEndBlock and a helper flag:

  • getQueryDetails(queryId) returns:
    • currentEndBlock — wait until block.number > currentEndBlock
    • inTieExtension — indicates the query is in an extended voting phase
    • canBeResolved — hint that a clear winner exists once the window is over

Typical flow:

  1. Read getQueryDetails(queryId).
  2. If block.number <= currentEndBlock, wait.
  3. If inTieExtension is true, wait for more blocks/votes.
  4. Call resolveQuery(queryId). If it reverts, re-read details and retry after extension.

Tie handling

On a tie among top answers:

  • Contract sets currentEndBlock = block.number + tieExtensionPeriod()
  • Emits VotingExtended(queryId, newEndBlock, uniqueWinners)
  • Reverts the transaction

Your contract can simply surface a failed attempt (boolean false via the try/catch pattern). Off-chain orchestration (indexers, bots, UIs) should then wait until currentEndBlock and try again.

Post‑resolution data

After a successful resolve:

  • getQueryDetails(queryId) returns resolved = true
  • winningOptions is the decoded uint8[] that won
  • Total rewards pot formula (for context to off-chain systems):
    • totalPot = initialDeposit + (totalCollateral - totalWinningCollateral)

If your contract has a winning vote, proceed to Claim (next page).

Common pitfalls

  • Resolving too early: ensure block.number > currentEndBlock
  • Ties: expect reverts that extend the window; handle retries gracefully
  • Assuming a winner without reading latest state: always re-read getQueryDetails

Back to: