hats-finance / SeeR-PM-0x899bc13919880db76edf4ccd72bdfa5dfa666fb7

1 stars 0 forks source link

We cannot create a market with more than ~75 outcomes, even though limit is set to 256 in prepareCondition() #66

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

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

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

Description:

Summary

The current limit to max outcomes is set to 256, usually 256 would be rare, however currently its not possible to even reach 75, which would be quite useful in cases where we have many possible outcomes like in Political Elections, Sports Tournaments, Gaming Tournaments, Oscars/Academy Awards where we could easily have more than 75 possible outcomes.

Vulnerability details

In prepareCondition() we set the max possible outcomeSlotCount:

    /// @dev This function prepares a condition by initializing a payout vector associated with the condition.
    /// @param oracle The account assigned to report the result for the prepared condition.
    /// @param questionId An identifier for the question to be answered by the oracle.
    /// @param outcomeSlotCount The number of outcome slots which should be used for this condition. Must not exceed 256.
    function prepareCondition(address oracle, bytes32 questionId, uint outcomeSlotCount) external {
        // Limit of 256 because we use a partition array that is a number of 256 bits.
@>>     require(outcomeSlotCount <= 256, "too many outcome slots");
        require(outcomeSlotCount > 1, "there should be more than one outcome slot");
        bytes32 conditionId = CTHelpers.getConditionId(oracle, questionId, outcomeSlotCount);
        require(payoutNumerators[conditionId].length == 0, "condition already prepared");
        payoutNumerators[conditionId] = new uint[](outcomeSlotCount);
        emit ConditionPreparation(conditionId, oracle, questionId, outcomeSlotCount);
}

This issue occurs because we will reach the limit per block of 30M gas around 75 set outcomes, which mean that this transaction won't be able to be executed as it won't fit in a single block, as the usual hard limit is 30 M.

If in constants.ts you add more possible outcomes:

export const multiCategoricalMarketParams = {
  marketName: "Which color will win?",
  encodedQuestions: ['Which color will win?␟"Red","Blue","Green","Yellow","Purple","Orange"␟misc␟en_US'],
  questionStart: "",
  questionEnd: "",
  outcomeType: "",
  parentOutcome: 0,
  parentMarket: ethers.ZeroAddress,
  category: "misc",
  lang: "en_US",
  outcomes: [
    "Red", "Blue", "Green", "Yellow", "Purple", "Orange", "Black", "White",
    "Gray", "Brown", "Pink", "Magenta", "Cyan", "Teal", "Lime", "Olive",
    "Maroon", "Navy", "Aquamarine", "Turquoise", "Silver", "Indigo", "Violet",
    "Gold", "Orchid", "Plum", "Azure", "Rose", "Crimson", "Fuchsia", "Amber",
    "Beige", "Bronze", "Chocolate", "Coral", "Copper", "Emerald", "Ivory",
    "Jade", "Lavender", "Lilac", "Mauve", "Mint", "Mustard", "Ochre",
    "Peach", "Pearl", "Periwinkle", "Ruby", "Saffron", "Sapphire", "Scarlet",
    "Tan", "Topaz", "Ultramarine", "Vermilion", "Zaffre", "Amethyst",
    "Burgundy", "Charcoal", "Denim", "Khaki", "Lemon", "Midnight", "Onyx",
    "Opal", "Papaya", "Pewter", "Sand", "Sepia", "Smoky Quartz", "Tangerine",
    "Umber", "Violet Red", "Wine", "Alabaster", "Burnt Sienna", "Cerulean",
  ],
  lowerBound: 0,
  upperBound: 0,
  minBond: ethers.parseEther(MIN_BOND),
  openingTime: 0,
  tokenNames: [
    "RED", "BLUE", "GREEN", "YELLOW", "PURPLE", "ORANGE", "BLACK", "WHITE",
    "GRAY", "BROWN", "PINK", "MAGENTA", "CYAN", "TEAL", "LIME", "OLIVE",
    "MAROON", "NAVY", "AQUAMARINE", "TURQUOISE", "SILVER", "INDIGO", "VIOLET",
    "GOLD", "ORCHID", "PLUM", "AZURE", "ROSE", "CRIMSON", "FUCHSIA", "AMBER",
    "BEIGE", "BRONZE", "CHOCOLATE", "CORAL", "COPPER", "EMERALD", "IVORY",
    "JADE", "LAVENDER", "LILAC", "MAUVE", "MINT", "MUSTARD", "OCHRE",
    "PEACH", "PEARL", "PERIWINKLE", "RUBY", "SAFFRON", "SAPPHIRE", "SCARLET",
    "TAN", "TOPAZ", "ULTRAMARINE", "VERMILION", "ZAFFRE", "AMETHYST",
    "BURGUNDY", "CHARCOAL", "DENIM", "KHAKI", "LEMON", "MIDNIGHT", "ONYX",
    "OPAL", "PAPAYA", "PEWTER", "SAND", "SEPIA", "SMOKY_QUARTZ", "TANGERINE",
    "UMBER", "VIOLET_RED", "WINE", "ALABASTER", "BURNT_SIENNA", "CERULEAN",
  ],

And then run a test with gasReporter on, for example npx hardhat test --grep "resolves a multi categorical market" you will get 28255005 gas for the createMultiCategoricalMarket


·----------------------------------------------------|----------------------------|-------------|-----------------------------·
|                Solc version: 0.4.18                ·  Optimizer enabled: false  ·  Runs: 200  ·  Block limit: 30000000 gas  │
·····················································|····························|·············|······························
|  Methods                                                                                                                    │
····················|································|··············|·············|·············|···············|··············
|  Contract         ·  Method                        ·  Min         ·  Max        ·  Avg        ·  # calls      ·  usd (avg)  │
····················|································|··············|·············|·············|···············|··············
|  MarketFactory    ·  createMultiCategoricalMarket  ·           -  ·          -  ·   28255005  ·            1  ·          -  │
····················|································|··············|·············|·············|···············|··············
|  RealityETH_v3_0  ·  submitAnswer                  ·           -  ·          -  ·     102925  ·            1  ·          -  │
····················|································|··············|·············|·············|···············|··············
|  RealityProxy     ·  resolve                       ·           -  ·          -  ·     418786  ·            2  ·          -  │

Impact

The max set outcomes cannot be reached and some events won't be possible to put markets on Seer.

clesaege commented 1 week ago

Keep in mind that the conditional token framework was developed by Gnosis, not Seer. So them supporting 256 outcomes doesn't mean that Seer intends to support this number (and yes it's lower as we do make positions ERC20 tokens which is more gas intensif than using ERC1115). Here it looks more like a feature request (allow more outcomes) than a report of vulnerabilities.