hats-finance / SeeR-PM-0x899bc13919880db76edf4ccd72bdfa5dfa666fb7

1 stars 0 forks source link

Unintended Market Resolution Due to Incorrect Reality.eth Question Opening Time #123

Open hats-bug-reporter[bot] opened 1 month ago

hats-bug-reporter[bot] commented 1 month ago

Github username: -- Twitter username: -- Submission hash (on-chain): 0x4dc4a8bee494100f2103fb12adc9d2fb24a785ccbc5ec3e15d4a2e88f907c52c Severity: medium

Description:

Details

The Seer Protocol's MarketFactory contract creates prediction markets linked to Reality.eth questions. The askRealityQuestion function is responsible for submitting these questions to Reality.eth.

The askRealityQuestion function uses a user-provided openingTime parameter when creating or reusing Reality.eth questions. However, it doesn't validate this parameter against the current block timestamp, potentially allowing the creation of markets with questions that open in the past.

Code Snippet

function askRealityQuestion(
    string memory encodedQuestion,
    uint256 templateId,
    uint32 openingTime,
    uint256 minBond
) internal returns (bytes32) {
    bytes32 content_hash = keccak256(abi.encodePacked(templateId, openingTime, encodedQuestion));
    bytes32 question_id = keccak256(
        abi.encodePacked(
            content_hash, arbitrator, questionTimeout, minBond, address(realitio), address(this), uint256(0)
        )
    );
    if (realitio.getTimeout(question_id) != 0) {
        return question_id;
    }
    return realitio.askQuestionWithMinBond(
        templateId, encodedQuestion, arbitrator, questionTimeout, openingTime, 0, minBond
    );
}

Impact

  1. Markets could be created with questions that are immediately open for answering, potentially leading to rapid and unexpected resolutions.
  2. Malicious actors could exploit this to create markets that resolve quickly based on past events, taking advantage of information asymmetry.
  3. The integrity of the prediction market system could be compromised, as markets might not provide a fair opportunity for all participants to engage.

Scenario

  1. A user creates a market with an openingTime set to a past timestamp.
  2. The Reality.eth question is immediately open for answering.
  3. The user or an accomplice quickly provides an answer to the question.
  4. The market resolves based on this answer before most participants are aware of its existence.

Probability

High. This issue can be easily triggered by any user creating a market, either accidentally or intentionally.

Fix

Implement a check in the askRealityQuestion function to ensure the openingTime is in the future:

function askRealityQuestion(
    string memory encodedQuestion,
    uint256 templateId,
    uint32 openingTime,
    uint256 minBond
) internal returns (bytes32) {
    require(openingTime > block.timestamp, "Opening time must be in the future");
    // Rest of the function remains the same
    ...
}

Consider adding an upper bound to the openingTime as well, to prevent markets from being created too far in the future.

Poc

describe("askRealityQuestion vulnerability", function () {
  it("allows creation of markets with questions opening in the past", async function () {
    const pastOpeningTime = await time.latest() - 3600; // 1 hour in the past
    const futureOpeningTime = await time.latest() + 3600; // 1 hour in the future

    // Create a market with a past opening time (this should ideally fail, but currently doesn't)
    await expect(
      marketFactory.createCategoricalMarket({
        ...categoricalMarketParams,
        openingTime: pastOpeningTime,
      })
    ).to.emit(marketFactory, "NewMarket");

    // Create a market with a future opening time (this should succeed)
    await expect(
      marketFactory.createCategoricalMarket({
        ...categoricalMarketParams,
        openingTime: futureOpeningTime,
      })
    ).to.emit(marketFactory, "NewMarket");

    // Check that both markets were created
    expect(await marketFactory.marketCount()).to.equal(2);

    // Get the created markets
    const markets = await marketFactory.allMarkets();
    const pastMarket = await ethers.getContractAt("Market", markets[0]);
    const futureMarket = await ethers.getContractAt("Market", markets[1]);

    // Check the opening times of the created questions
    const pastQuestionId = (await pastMarket.questionsIds())[0];
    const futureQuestionId = (await futureMarket.questionsIds())[0];

    const pastQuestionOpeningTime = await realitio.getOpeningTS(pastQuestionId);
    const futureQuestionOpeningTime = await realitio.getOpeningTS(futureQuestionId);

    // Both should be in the past and future respectively
    expect(pastQuestionOpeningTime).to.be.lt(await time.latest());
    expect(futureQuestionOpeningTime).to.be.gt(await time.latest());

    // Demonstrate that the past market can be answered immediately
    const answerer = (await ethers.getSigners())[1];
    await realitio.connect(answerer).submitAnswer(
      pastQuestionId,
      ethers.encodeBytes32String("1"), // Assuming "1" is a valid answer
      0, // Current bond
      { value: ethers.parseEther(MIN_BOND) }
    );

    // Check that the answer was accepted
    const lastAnswerTime = await realitio.getAnswerTimestamp(pastQuestionId);
    expect(lastAnswerTime).to.be.gt(0);
  });
});

This test does the following:

  1. It creates two markets: one with an opening time in the past and one in the future.
  2. It verifies that both markets are created successfully (which demonstrates the bug, as the past market should ideally fail).
  3. It checks the actual opening times of the Reality.eth questions for both markets.
  4. It demonstrates that the market with the past opening time can be answered immediately, which shouldn't be possible in a properly functioning system.
greenlucid commented 1 month ago

https://github.com/hats-finance/SeeR-PM-0x899bc13919880db76edf4ccd72bdfa5dfa666fb7/issues/26#issuecomment-2375274370

Use search function next time you submit an issue. Dupe, invalid

clesaege commented 1 month ago

Similar to https://github.com/hats-finance/SeeR-PM-0x899bc13919880db76edf4ccd72bdfa5dfa666fb7/issues/26#issuecomment-2375274370